home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / ANIVGA.ARJ / ANIVGA.PAS < prev    next >
Pascal/Delphi Source File  |  1991-11-09  |  209KB  |  6,347 lines

  1. {$A+,B-,D+,E-,O-,R-,S-,V-}
  2. {$M 16384,0,655360}
  3.  
  4. {Programmtool zur Realisierung schneller Animationen auf der VGA-Grafik-    }
  5. {karte von: Kai Rohrbacher, 1988-1991, Turbo-Pascal 6.0                     }
  6.  
  7. { Features:                                                                 }
  8.  
  9. { - flickerfreie Animation durch page-flipping, Auswertung des vertikalen   }
  10. {   Retracesignals und Verwendung eines speziellen VGA-256-Farbengrafikmodus}
  11. { - Spritebewegung pixelweise (und nicht nur byteweise) moeglich            }
  12. { - beliebiges Hintergrundbild, vor der die Animation geschieht             }
  13. { - volle Unterstuetzung der 256-Farbmoeglichkeiten der VGA-Karte           }
  14. { - verschiedene Spritedarstellungsmoeglichkeiten:                          }
  15. {   - Sprites koennen pixelweise als durchsichtig gegenueber dem Hintergrund}
  16. {     deklariert werden                                                     }
  17. {   - Sprites koennen ihre Farbe in Abhaengigkeit ihres momentanen Hinter-  }
  18. {     grundes veraendern ("Schattenfunktion")                               }
  19. { - Routine zur exakten Feststellung der Kollision zweier Sprites           }
  20. { - Sprites werden beim Verschwinden an einer der Bildschirmgrenzen korrekt }
  21. {   abgeschnitten                                                           }
  22. { - Verwaltung von bis zu 1000 verschiedenen Sprites                        }
  23. { - gleichzeitige Darstellung von bis zu 500 Sprites                        }
  24. { - maximale Spritegroesse 64k                                              }
  25. { - maximaler Umfang aller Sprites zusammen nur durch Hauptspeicher begrenzt}
  26. { - arbeitet mit virtuellen Koordinaten im Bereich -16000..+16000, daher    }
  27. {   einfaches horizontales und vertikales Scrolling moeglich                }
  28. { - Scrollbares Hintergrundbild ebenfalls unterstuetzt                      }
  29. { - viele unterstuetzende Routinen: zeichnen von Linien (mit eingebautem    }
  30. {   Clipping-Algorithmus), Punkten und Grafik-Text (dto.), automatische Ver-}
  31. {   waltungs des Heaps zum Speichern/Laden von Sprites, Hintergrundbildern, }
  32. {   Aendern von Spritedarstellungsmodi waehrend der Laufzeit, Geschwindig-  }
  33. {   keitsanpassung an unterschiedlich schnelle Rechner, ...                 }
  34.  
  35.  
  36. UNIT ANIVGA;
  37. INTERFACE
  38.  
  39. USES CRT,DOS;
  40.  
  41. CONST NMAX=499;
  42.       XMAX=319;
  43.       YMAX=199;
  44.       LoadMAX=1000;  {max. Anzahl an gleichzeitig geladenenen Sprites}
  45.       LINESIZE=(XMAX+1) DIV 4;    {Groesse einer Zeile=80 Bytes}
  46.       PAGESIZE=(YMAX+1)*LINESIZE; {200 Zeilen zu je 320/4 Bytes}
  47.       BACKGNDPAGE=2;
  48.       SCROLLPAGE=3;
  49.  
  50.       STATIC=0;      {Konstanten fuer Hintergrundart}
  51.       SCROLLING=1;
  52.  
  53.       MaxTiles=10000;  {max. Anzahl an Hintergrund-Kacheln}
  54.       StartVirtualX:INTEGER=0;  {obere linke Bildschirmecke}
  55.       StartVirtualY:INTEGER=0;
  56.  
  57.       {unterstuetzte Darstellungsmodi der Sprites: }
  58.       Display_NORMAL=0;   {normal  : durchsichtig fuer Farbe 0}
  59.       Display_FAST  =1;   {schnell : keine Hintergrundberuecksichtigung}
  60.       Display_SHADOW=2;   {Schatten: Farbumsetzung anhand des Hintergrundes}
  61.       Display_UNKNOWN=255;{Fehlerwert}
  62.  
  63.       {Fehlercodes des Animationspaketes: }
  64.       Err_None=0;
  65.       Err_NotEnoughMemory=1;
  66.       Err_FileIO=2;
  67.       Err_InvalidSpriteNumber=3;
  68.       Err_NoSprite=4;
  69.       Err_InvalidPageNumber=5;
  70.       Err_NoVGA=6;
  71.       Err_NoPicture=7;
  72.       Err_InvalidPercentage=8;
  73.       Err_NoTile=9;
  74.       Err_InvalidTileNumber=10;
  75.       Err_InvalidCoordinates=11;
  76.       Err_BackgroundToBig=12;
  77.       Err_InvalidMode=13;
  78.       Err_InvalidSpriteLoadNumber=3;
  79.  
  80. TYPE  FontChar=ARRAY[0..5] OF BYTE;
  81.       Font=ARRAY[0..255] OF Fontchar;
  82.       FontOrient=(horizontal,vertical);    {moegliche Textausgaberichtungen}
  83. CONST GraphTextOrientation:FontOrient=horizontal; {aktuelle Ausgaberichtung}
  84.       GraphTextColor:BYTE=white;           {aktuelle Textausgabefarben}
  85.       GraphTextBackground:BYTE=white;
  86.       FontHeight=6;
  87.       FontWidth=6;
  88.  
  89. TYPE Table=ARRAY[0..NMAX] OF INTEGER;
  90.      ColorTable=ARRAY[0..255] OF BYTE;
  91.  
  92.  
  93. VAR Error:BYTE; {globale Fehlervariable}
  94.     SpriteN:Table;
  95.     SpriteX:Table;
  96.     SpriteY:Table;
  97.     NextSprite:ARRAY[0..LoadMAX] OF WORD;
  98.     SPRITEAD:ARRAY[0..LoadMAX] OF WORD;
  99.     PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
  100.     Color:BYTE;           {Zeichenfarbe fuer Linien}
  101.     was_cut:BOOLEAN;      {TRUE/FALSE, falls "GetImage" clippen musste  }
  102.     left_cut,             {Var., die durch "GetImage" gesetzt werden und}
  103.     right_cut,            {bei "was_cut"=TRUE darueber Auskunft geben,  }
  104.     top_cut,              {wo und wieviel des Bildes abgeschnitten wer- }
  105.     bottom_cut:WORD;      {den musste                                   }
  106.  
  107.     BackgroundMode:BYTE;
  108.     BackTile:ARRAY[0..MaxTiles-1] OF BYTE;  {Kachelnspeicher}
  109.     XTiles,YTiles:INTEGER;                  {Breite,Hoehe des def. Bereiches}
  110.     BackX1,BackY1,BackX2,BackY2:INTEGER;    {Koordinaten des def. Bereiches }
  111.  
  112.  
  113.  PROCEDURE ShadowTab;
  114.  PROCEDURE SetShadowTab(brightness:BYTE);
  115.  PROCEDURE SetCycleTime(milliseconds:WORD);
  116.  PROCEDURE SetSpriteCycle(nr,len:WORD);
  117.  FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
  118.  PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
  119.  PROCEDURE InitGraph;
  120.  PROCEDURE Screen(pa:BYTE);
  121.  PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
  122.  PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
  123.  FUNCTION GetPixel(x,y:INTEGER):BYTE;
  124.  FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
  125.  FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE;
  126.  PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
  127.  PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
  128.  PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte);
  129.  PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
  130.  PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
  131.  FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
  132.  PROCEDURE Animate;
  133.  FUNCTION LoadSprite(name:String; number:WORD):WORD;
  134.  FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
  135.  PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
  136.  PROCEDURE SetBackgroundMode(mode:BYTE);
  137.  PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
  138.  PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
  139.  FUNCTION GetModeByte(Sp:WORD):BYTE;
  140.  PROCEDURE FillPage(pa,color:Byte);
  141.  PROCEDURE FillBackground(color:BYTE);
  142.  PROCEDURE GetBackgroundFromPage(pa:Byte);
  143.  PROCEDURE WritePage(name:STRING; pa:BYTE);
  144.  PROCEDURE LoadPage(name:STRING; pa:BYTE);
  145.  PROCEDURE WriteBackgroundPage(name:STRING);
  146.  PROCEDURE LoadBackgroundPage(name:STRING);
  147.  PROCEDURE InitRoutines;
  148.  PROCEDURE CloseRoutines;
  149.  FUNCTION GetErrorMessage:STRING;
  150.  
  151.  
  152. {--------------------------------------------------------------------------}
  153.  
  154. IMPLEMENTATION
  155.  
  156. CONST StartIndex=0;
  157.       EndIndex=StartIndex+3;
  158.       {Offsetadressen der Grafikseiten (in Segment $A000):}
  159.       Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
  160.       {Segmentadressen der Grafikseiten (bei Offset = 0) :}
  161.       Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
  162.  
  163.       {Sprite(header)aufbau:
  164.  
  165.       0..1   DW Plane_0_Daten
  166.       2..3   DW Plane_1_Daten
  167.       4..5   DW Plane_2_Daten
  168.       6..7   DW Plane_3_Daten
  169.       8..9   DW Breite (in 4er-Gruppen)
  170.       10..11 DW Hoehe in Zeilen
  171.       12..15 DB 1,2,4,8      ; Translate-Tabelle fuer Port-Ansteuerung
  172.       16..17 DW SpriteLength ; Laenge der Spritedatei
  173.                              ; jetzt fuer temporaere Variablen reservierter
  174.                              ; Bereich:
  175.       18..19 DW ?            ; licutoff_      | hit1xfirst
  176.       20..21 DW ?            ; zeilenadr      | hit1yfirst
  177.       22..23 DW ?            ; bildx          | hit2xfirst
  178.       24..25 DW ?            ; yoffset_       | hit2yfirst
  179.       26..27 DW ?            ; end_min_start  | ueberlappx_1
  180.       28..29 DW ?            ;                | ueberlappy_1
  181.       30..31 DW ?            ;                | x1
  182.       32..33 DW ?            ;                | x2
  183.       34..35 DW ?            ;                | y1
  184.       36..37 DW ?            ;                | y2
  185.       38..39 DB 'K','R'      ; Kennung als Sprite
  186.       40     DB 1            ; Versionsnummer
  187.       41     DB 0            ; Modusnummer fuer Sprite
  188.       42..43 DW linke_Begrenzungen
  189.       44..45 DW rechte_Begrenzungen
  190.       46..47 DW obere_Begrenzungen
  191.       48..49 DW untere_Begrenzungen
  192.       50..?? DB Daten
  193.  
  194.       zum Bsp.:  xxrxxxxx, mit: r=rot=40, g=gruen=45, b=blau=35, x=weiss=30
  195.                  xrgrxxxx
  196.                  rbgbrxxx
  197.       }
  198.  
  199.       {Adressen von wichtigen Werten innerhalb des Spriteheaders:}
  200.       Left=42;
  201.       Right=44;
  202.       Top=46;
  203.       Bottom=48;
  204.       Breite=8;
  205.       Hoehe=10;
  206.       Translate=12;
  207.       SpriteLength=16;
  208.       Kennung=38;
  209.       Version=40;
  210.       Modus=41;
  211.  
  212.       {Adressen der temporaeren Variablen fuer die Zeichenroutinen:}
  213.       licutoff_=18;
  214.       zeilenadr=20;
  215.       bildx=22;
  216.       yoffset_=24;
  217.       end_min_start=26;
  218.  
  219.       {Adressen der temporaeren Variablen fuer die Zeichenroutinen:}
  220.       hit1xfirst=18;
  221.       hit1yfirst=20;
  222.       hit2xfirst=22;
  223.       hit2yfirst=24;
  224.       ueberlappx_1=26;
  225.       ueberlappy_1=28;
  226.       x1=30;
  227.       x2=32;
  228.       y1=34;
  229.       y2=36;
  230.  
  231.       TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {Fuer Maskenadressierung}
  232.       PICHeader:STRING[3]='PIC'; {Kennung in Bilderdateien}
  233.  
  234. TYPE SpriteHeader= RECORD
  235.                     Zeiger_auf_Plane:Array[0..3] OF Word;
  236.                     Breite_in_4er_Gruppen:WORD;
  237.                     Hoehe_in_Zeilen:WORD;
  238.                     Translate:Array[1..4] OF Byte;
  239.                     SpriteLength:WORD;
  240.                     Dummy:Array[1..10] OF Word;
  241.                     Kennung:ARRAY[1..2] OF CHAR;
  242.                     Version:BYTE;
  243.                     Modus:BYTE;
  244.                     ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
  245.                    END;
  246.  
  247. CONST FontMask:ARRAY[0..7] OF BYTE=($80,$40,$20,$10,8,4,2,1);
  248.       FontData: Font=(                   {verwendeter Zeichensatz:  }
  249.       (  0,  0,  0,  0,  0,  0), {#0}    {selbstgestrickter 6x6 Font}
  250.       (  0,216,  0,248,112,  0), {#1}
  251.       (248,168,248,136,216,248), {#2}
  252.       (  0, 80,248,248,112, 32), {#3}
  253.       (  0, 32,112,248,112, 32), {#4}
  254.       ( 32,112,216,248, 32,112), {#5}
  255.       ( 32,112,248,248, 32,112), {#6}
  256.       (  0, 32,216,216, 32,  0), {#7}
  257.       (248,216,168,168,216,248), {#8}
  258.       (  0,112,200,152,112,  0), {#9}
  259.       (248,136,168,168,136,248), {#10}
  260.       ( 56, 24, 32,112,136,112), {#11}
  261.       (112,136,112, 32,248, 32), {#12}
  262.       ( 56, 40, 32, 32,224,224), {#13}
  263.       (  0,120, 72,120, 72,216), {#14}
  264.       (  0, 32,168, 80,168, 32), {#15}
  265.       (  0,128,224,248,224,128), {#16}
  266.       (  0,  8, 56,248, 56,  8), {#17}
  267.       ( 32,112,168,168,112, 32), {#18}
  268.       (  0,216,216,216,  0,216), {#19}
  269.       (  0,120,168,104, 40, 40), {#20}
  270.       ( 24, 32, 16, 40,144, 96), {#21}
  271.       (  0,  0,  0,  0,248,248), {#22}
  272.       ( 32,112, 32,112, 32,248), {#23}
  273.       (  0, 32,112,248, 32, 32), {#24}
  274.       (  0, 32, 32,248,112, 32), {#25}
  275.       (  0, 32, 16,248, 16, 32), {#26}
  276.       (  0, 32, 64,248, 64, 32), {#27}
  277.       (  0,  0,192,248,  0,  0), {#28}
  278.       (  0,  0, 80,248, 80,  0), {#29}
  279.       (  0,  0,  0, 32,112,248), {#30}
  280.       (  0,  0,248,112, 32,  0), {#31}
  281.       (  0,  0,  0,  0,  0,  0), { }
  282.       (  0, 48, 48, 48,  0, 48), {!}
  283.       (  0, 80, 80,  0,  0,  0), {"}
  284.       (  0, 80,248, 80,248, 80), {#}
  285.       ( 32,120,160,112, 40,240), { $}
  286.       (  0,200, 16, 32, 64,152), {%}
  287.       (  0,112,216,112,152,104), {&}
  288.       (  0, 16, 32,  0,  0,  0), {'}
  289.       (  0,112,192,192,192,112), {(}
  290.       (  0,224, 48, 48, 48,224), {)}
  291.       (  0, 80, 32,248, 32, 80), {*}
  292.       (  0,  0, 32,248, 32,  0), {+}
  293.       (  0,  0,  0, 32, 32, 64), {,}
  294.       (  0,  0,  0,248,  0,  0), {-}
  295.       (  0,  0,  0,  0, 48,  0), {.}
  296.       (  4,  8, 16, 32, 64,128), {/}
  297.       (  0,112,152,168,200,112), {0}
  298.       (  0, 48,112, 48, 48,120), {1}
  299.       (  0,240, 24,112,192,248), {2}
  300.       (  0,240, 24,112, 24,240), {3}
  301.       (  0,192,208,248, 48, 48), {4}
  302.       (  0,248,192,240, 24,240), {5}
  303.       (  0,248,128,248,136,248), {6}
  304.       (  0,248, 24, 48, 96, 96), {7}
  305.       (  0,112,216,112,216,112), {8}
  306.       (  0,112,136,120,  8,112), {9}
  307.       (  0,  0, 32,  0, 32,  0), {:}
  308.       (  0,  0, 32,  0, 32, 64), {;}
  309.       (  0, 24, 48, 96, 48, 24), {<}
  310.       (  0,  0,248,  0,248,  0), {=}
  311.       (  0, 96, 48, 24, 48, 96), {>}
  312.       (112,136, 16, 32,  0, 32), {?}
  313.       (  0,112,136,184,128,120), {@}
  314.       (  0,112,200,248,200,200), {A}
  315.       (  0,240,200,240,200,240), {B}
  316.       (  0,120,192,192,192,120), {C}
  317.       (  0,240,216,200,216,240), {D}
  318.       (  0,248,192,240,192,248), {E}
  319.       (  0,248,192,240,192,192), {F}
  320.       (  0,120,192,216,200,120), {G}
  321.       (  0,200,200,248,200,200), {H}
  322.       (  0,120, 48, 48, 48,120), {I}
  323.       (  0,248,  8,  8,200,112), {J}
  324.       (  0,200,208,224,208,200), {K}
  325.       (  0,192,192,192,192,248), {L}
  326.       (  0,136,216,168,136,136), {M}
  327.       (  0,136,200,168,152,136), {N}
  328.       (  0,112,200,200,200,112), {O}
  329.       (  0,240,200,240,192,192), {P}
  330.       (  0, 96,208,208,208,104), {Q}
  331.       (  0,240,136,240,208,200), {R}
  332.       (  0,248,192,248, 24,248), {S}
  333.       (  0,248, 96, 96, 96, 96), {T}
  334.       (  0,200,200,200,200,248), {U}
  335.       (  0,200,200,200,200, 48), {V}
  336.       (  0,136,136,168,248, 80), {W}
  337.       (  0,136,216,112,216,136), {X}
  338.       (  0,200,200,112, 48, 48), {Y}
  339.       (  0,248, 24,112,192,248), {Z}
  340.       (  0,120, 96, 96, 96,120), {[}
  341.       (128, 64, 32, 16,  8,  4), {\}
  342.       (  0,120, 24, 24, 24,120), {]}
  343.       ( 32, 80,136,  0,  0,  0), {^}
  344.       (  0,  0,  0,  0,  0,248), {_}
  345.       ( 64, 32,  0,  0,  0,  0), {`}
  346.       (  0,  0,112,200,200,120), {a}
  347.       (  0,128,240,136,136,240), {b}
  348.       (  0,  0,120,192,192,120), {c}
  349.       (  0,  8,120,136,136,120), {d}
  350.       (  0,  0,112,248,128,112), {e}
  351.       (  0, 24, 32,120, 32, 32), {f}
  352.       (  0,112,136,120,  8,112), {g}
  353.       (  0,192,240,200,200,200), {h}
  354.       ( 48,  0, 48, 48, 48, 48), {i}
  355.       ( 24,  0, 24, 24,216,112), {j}
  356.       (  0,192,208,224,216,216), {k}
  357.       (  0, 96, 96, 96, 96, 56), {l}
  358.       (  0,  0,208,248,168,136), {m}
  359.       (  0,  0,240,200,200,200), {n}
  360.       (  0,  0,112,200,200,112), {o}
  361.       (  0,  0,240,200,240,192), {p}
  362.       (  0,  0,112,152,120, 24), {q}
  363.       (  0,  0,176,104, 96, 96), {r}
  364.       (  0, 56, 64, 48,136,112), {s}
  365.       (  0, 96,248, 96,104, 48), {t}
  366.       (  0,  0,200,200,200,120), {u}
  367.       (  0,  0,200,200,200,112), {v}
  368.       (  0,  0,136,168,168,112), {w}
  369.       (  0,  0,216, 96, 48,216), {x}
  370.       (  0,  0,200,248,  8,112), {y}
  371.       (  0,  0,240, 48,192,248), {z}
  372.       (  0, 56, 96,192, 96, 56),(*{*)
  373.       (  0, 16, 16,  0, 16, 16), {|}
  374.       (  0,224, 48, 24, 48,224),(*}*)
  375.       (  0,104,144,  0,  0,  0), {~}
  376.       (  0, 32, 80,136,248,  0), {#127}
  377.       (112,200,128,200,112,192), {#128}
  378.       (  0,200,  0,200,200,120), {#129}
  379.       ( 24, 32,112,248,128,112), {#130}
  380.       ( 16, 40,  0,120,196,124), {#131}
  381.       (104,  0,112,200,200,120), {#132}
  382.       ( 48,  8,112,136,136,120), {#133}
  383.       ( 16, 40, 16,112,200,120), {#134}
  384.       (  0,120,192,120, 16, 96), {#135}
  385.       (112,  0,112,248,192,112), {#136}
  386.       ( 80,  0,112,248,128,112), {#137}
  387.       ( 48,  8,112,248,192,112), {#138}
  388.       (104,  0, 48, 48, 48, 48), {#139}
  389.       ( 48, 72,  0, 48, 48, 48), {#140}
  390.       ( 96, 16,  0, 48, 48, 48), {#141}
  391.       (200,  0,112,200,248,200), {#142}
  392.       ( 48,  0,112,200,248,200), {#143}
  393.       (112,248,192,240,192,248), {#144}
  394.       (  0,208, 40,112,160, 88), {#145}
  395.       (  0, 56, 80,248,144,152), {#146}
  396.       ( 32, 80,  0,112,200,112), {#147}
  397.       ( 80,  0,112,200,200,112), {#148}
  398.       ( 96, 16,  0,112,200,112), {#149}
  399.       ( 32, 80,  0,200,200,120), {#150}
  400.       ( 96, 16,  0,200,200,120), {#151}
  401.       ( 80,  0,200,248,  8,112), {#152}
  402.       ( 80,  0,112,200,200,112), {#153}
  403.       (200,  0,200,200,200,248), {#154}
  404.       ( 16,120,128,128,120, 16), {#155}
  405.       ( 48, 72,224, 64,136,248), {#156}
  406.       (216, 32,248, 32,248, 32), {#157}
  407.       (192,160,208,184,144,152), {#158}
  408.       ( 48, 40, 96, 48,160, 96), {#159}
  409.       ( 48, 64,  0,112,136,120), {#160}
  410.       ( 48, 64,  0, 32, 32, 32), {#161}
  411.       ( 48, 64,  0,112,200,112), {#162}
  412.       ( 48, 64,  0,200,200,120), {#163}
  413.       (104,144,  0,176, 72, 72), {#164}
  414.       (104,144,  0,200,168,152), {#165}
  415.       (112,144,104,  0,248,  0), {#166}
  416.       (112,136,112,  0,248,  0), {#167}
  417.       ( 32,  0, 32, 64,136,112), {#168}
  418.       (  0,  0,252,192,  0,  0), {#169}
  419.       (  0,  0,252, 12,  0,  0), {#170}
  420.       ( 72, 80, 32, 64,168, 40), {#171}
  421.       ( 72, 80, 32, 80,152,  8), {#172}
  422.       ( 48,  0, 48, 48, 48,  0), {#173}
  423.       ( 40, 80,160, 80, 40,  0), {#174}
  424.       (160, 80, 40, 80,160,  0), {#175}
  425.       ( 84,168, 84,168, 84,168), {#176}
  426.       (252,252,252,252,252,252), {#177}
  427.       (168, 84,168, 84,168, 84), {#178}
  428.       ( 16, 16, 16, 16, 16, 16), {#179}
  429.       ( 16, 16, 16,240, 16, 16), {#180}
  430.       ( 16, 16,240, 16,240, 16), {#181}
  431.       ( 40, 40, 40,232, 40, 40), {#182}
  432.       (  0,  0,  0,248, 40, 40), {#183}
  433.       (  0,  0,240, 16,240, 16), {#184}
  434.       ( 40, 40,232,  8,232, 40), {#185}
  435.       ( 40, 40, 40, 40, 40, 40), {#186}
  436.       (  0,  0,248,  8,232, 40), {#187}
  437.       ( 40, 40,232,  8,248,  0), {#188}
  438.       ( 40, 40, 40,248,  0,  0), {#189}
  439.       ( 16, 16,240, 16,240,  0), {#190}
  440.       (  0,  0,  0,240, 16, 16), {#191}
  441.       ( 16, 16, 16, 28,  0,  0), {#192}
  442.       ( 16, 16, 16,252,  0,  0), {#193}
  443.       (  0,  0,  0,252, 16, 16), {#194}
  444.       ( 16, 16, 16, 28, 16, 16), {#195}
  445.       (  0,  0,  0,252,  0,  0), {#196}
  446.       ( 16, 16, 16,252, 16, 16), {#197}
  447.       ( 16, 16, 28, 16, 28, 16), {#198}
  448.       ( 40, 40, 40, 44, 40, 40), {#199}
  449.       ( 40, 40, 44, 32, 60,  0), {#200}
  450.       (  0,  0, 60, 32, 44, 40), {#201}
  451.       ( 40, 40,236,  0,252,  0), {#202}
  452.       (  0,  0,252,  0,236, 40), {#203}
  453.       ( 40, 40, 44, 32, 44, 40), {#204}
  454.       (  0,  0,252,  0,252,  0), {#205}
  455.       ( 40, 40,236,  0,236, 40), {#206}
  456.       ( 16, 16,252,  0,252,  0), {#207}
  457.       ( 40, 40, 40,252,  0,  0), {#208}
  458.       (  0,  0,252,  0,252, 16), {#209}
  459.       (  0,  0,  0,252, 40, 40), {#210}
  460.       ( 40, 40, 40, 60,  0,  0), {#211}
  461.       ( 16, 16, 28, 16, 28,  0), {#212}
  462.       (  0,  0, 28, 16, 28, 16), {#213}
  463.       (  0,  0,  0, 60, 40, 40), {#214}
  464.       ( 40, 40, 40,252, 40, 40), {#215}
  465.       ( 16, 16,252, 16,252, 16), {#216}
  466.       ( 16, 16, 16,240,  0,  0), {#217}
  467.       (  0,  0, 28, 16, 16, 16), {#218}
  468.       (252,252,252,252,252,252), {#219}
  469.       (  0,  0,  0,252,252,252), {#220}
  470.       (192,192,192,192,192,192), {#221}
  471.       ( 12, 12, 12, 12, 12, 12), {#222}
  472.       (252,252,252,  0,  0,  0), {#223}
  473.       (  0,  0,104,144,144,104), {#224}
  474.       (  0,112,152,176,136,176), {#225}
  475.       (  0,248,136,128,128,128), {#226}
  476.       (  0,  0,248, 80, 80, 80), {#227}
  477.       (248, 72, 32, 64,136,248), {#228}
  478.       (  0,  0,120,144,144, 96), {#229}
  479.       (  0, 72, 72,120, 64,192), {#230}
  480.       (  0,  0,104,176, 32, 32), {#231}
  481.       (  0,248, 32, 80, 32,248), {#232}
  482.       (  0,112,136,248,136,112), {#233}
  483.       (  0,112,136,136, 80,216), {#234}
  484.       ( 56, 64, 32,112,136,112), {#235}
  485.       (  0,  0, 80,168, 80,  0), {#236}
  486.       (  0,  8, 80,168, 80,128), {#237}
  487.       (  0,120,128,248,128,120), {#238}
  488.       (  0,  0,112,136,136,136), {#239}
  489.       (  0,248,  0,248,  0,248), {#240}
  490.       (  0, 32,112, 32,  0,248), {#241}
  491.       ( 64, 32, 16, 32, 64,248), {#242}
  492.       ( 16, 32, 64, 32, 16,248), {#243}
  493.       ( 16, 40, 32, 32, 32, 32), {#244}
  494.       ( 32, 32, 32, 32,160, 64), {#245}
  495.       (  0, 32,  0,248,  0, 32), {#246}
  496.       (104,144,  0,104,144,  0), {#247}
  497.       ( 96,144, 96,  0,  0,  0), {#248}
  498.       (  0,  0,  0, 48,  0,  0), {#249}
  499.       (  0,  0,  0, 16,  0,  0), {#250}
  500.       ( 60, 32, 32,160, 96, 32), {#251}
  501.       (176, 72, 72,  0,  0,  0), {#252}
  502.       (224, 16, 96,128,240,  0), {#253}
  503.       (  0,  0,112,112,  0,  0), {#254}
  504.       (  0,  0,  0,  0,  0,  0));{#255}
  505.  
  506. VAR Steigung:BYTE;        {entscheidet, welcher Alg. Anwendung findet}
  507.     DY_mal2,DY_m_DX_mal2:INTEGER;
  508.     oldMode:byte;
  509.     regs:registers;
  510.  
  511.     IsAT:BYTE;
  512.     TimeFlag:BYTE;
  513.     CycleTime:LONGINT;
  514.  
  515.  
  516. {-----------------------------------------------------}
  517.  
  518. PROCEDURE ShadowTab; ASSEMBLER;
  519. {Pseudoprozedur, um Daten der Farbumsetztabelle im Codesegment unterzu-}
  520. {bringen, AUF KEINEN FALL AUFRUFEN!!!                                  }
  521. {Defaultwerte entsprechen Abdunkelung auf 70% des Farb-Helligkeitswerts}
  522. ASM
  523.    DB 254,104,120,124,112,108,114, 24, 20,128,144,  3,136,  5,140,  7
  524.    DB 254,254, 17, 17, 18, 19, 20, 20, 21,  8, 23, 24, 24, 25, 26,  7
  525.    DB   1,  1,107,108,  5,108,109,  4,  4,  4,  6,  6,116,116,117,  2
  526.    DB   2,  2,123,124,  3,124,125,  1,152,155,156,156,  5,156,156,157
  527.    DB 160,163,164,164,164,164,164,165,168,171,172,172,  3,172,172,173
  528.    DB  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
  529.    DB  24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
  530.    DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
  531.    DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
  532.    DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
  533.    DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
  534.    DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
  535.    DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
  536.    DB  17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
  537.    DB  17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
  538.    DB  17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254,  7
  539. END;
  540.  
  541. PROCEDURE CS_TranslateTab; ASSEMBLER;
  542. {kleine Pseudoprozedur, um die Umsetztabelle fuer die Bitmaske auch im}
  543. {Codesegment zu haben}
  544. ASM
  545.  DB 1,2,4,8
  546. END;
  547.  
  548. PROCEDURE SetShadowTab(brightness:BYTE);
  549. { in: brightness = gewuenschte Helligkeit der Farben im Schattenbereich,}
  550. {                  in Prozent zu der Helligkeit ihrer Originalfarben    }
  551. {out: ShadowTab  = (Naeherungs-)Farbtabelle fuer gewuenschte Abdunkelung}
  552. {rem: Defaultwert in ShadowTab ist 70% Helligkeit der Ursprungsfarben!  }
  553. {     Diese Routine dauert ihre Zeit (ca. 4 sec auf 8MHz-AT!)           }
  554. TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
  555.      Palette=ARRAY[0..255] OF PaletteEntry;
  556. CONST default_Farben:Palette=      {Defaultfarben-Palette des 256-Farbmodus}
  557.  (                                 {ausgelesen mithilfe des BIOS-Aufrufs:  }
  558.   (red:  0; green:  0; blue:  0),  { MOV AX,1017h ;lese Palettenregister}
  559.   (red:  0; green:  0; blue: 42),  { XOR BX,BX    ;von Farbe 0 an }
  560.   (red:  0; green: 42; blue:  0),  { MOV CX,100h  ;alle 256 Farben}
  561.   (red:  0; green: 42; blue: 42),  { LES DX,Ziel  ;nach ES:DX }
  562.   (red: 42; green:  0; blue:  0),  { INT 10h }
  563.   (red: 42; green:  0; blue: 42),  {Achtung! Die Werte koenn(t)en nur dann }
  564.   (red: 42; green: 21; blue:  0),  {ausgelesen werden, wenn der Grafikmodus}
  565.   (red: 42; green: 42; blue: 42),  {bereits aktiv ist, deshalb wurden sie  }
  566.   (red: 21; green: 21; blue: 21),  {hier "statisch" aufgenommen!}
  567.   (red: 21; green: 21; blue: 63),
  568.   (red: 21; green: 63; blue: 21),
  569.   (red: 21; green: 63; blue: 63),
  570.   (red: 63; green: 21; blue: 21),
  571.   (red: 63; green: 21; blue: 63),
  572.   (red: 63; green: 63; blue: 21),
  573.   (red: 63; green: 63; blue: 63),
  574.   (red:  0; green:  0; blue:  0),
  575.   (red:  5; green:  5; blue:  5),
  576.   (red:  8; green:  8; blue:  8),
  577.   (red: 11; green: 11; blue: 11),
  578.   (red: 14; green: 14; blue: 14),
  579.   (red: 17; green: 17; blue: 17),
  580.   (red: 20; green: 20; blue: 20),
  581.   (red: 24; green: 24; blue: 24),
  582.   (red: 28; green: 28; blue: 28),
  583.   (red: 32; green: 32; blue: 32),
  584.   (red: 36; green: 36; blue: 36),
  585.   (red: 40; green: 40; blue: 40),
  586.   (red: 45; green: 45; blue: 45),
  587.   (red: 50; green: 50; blue: 50),
  588.   (red: 56; green: 56; blue: 56),
  589.   (red: 63; green: 63; blue: 63),
  590.   (red:  0; green:  0; blue: 63),
  591.   (red: 16; green:  0; blue: 63),
  592.   (red: 31; green:  0; blue: 63),
  593.   (red: 47; green:  0; blue: 63),
  594.   (red: 63; green:  0; blue: 63),
  595.   (red: 63; green:  0; blue: 47),
  596.   (red: 63; green:  0; blue: 31),
  597.   (red: 63; green:  0; blue: 16),
  598.   (red: 63; green:  0; blue:  0),
  599.   (red: 63; green: 16; blue:  0),
  600.   (red: 63; green: 31; blue:  0),
  601.   (red: 63; green: 47; blue:  0),
  602.   (red: 63; green: 63; blue:  0),
  603.   (red: 47; green: 63; blue:  0),
  604.   (red: 31; green: 63; blue:  0),
  605.   (red: 16; green: 63; blue:  0),
  606.   (red:  0; green: 63; blue:  0),
  607.   (red:  0; green: 63; blue: 16),
  608.   (red:  0; green: 63; blue: 31),
  609.   (red:  0; green: 63; blue: 47),
  610.   (red:  0; green: 63; blue: 63),
  611.   (red:  0; green: 47; blue: 63),
  612.   (red:  0; green: 31; blue: 63),
  613.   (red:  0; green: 16; blue: 63),
  614.   (red: 31; green: 31; blue: 63),
  615.   (red: 39; green: 31; blue: 63),
  616.   (red: 47; green: 31; blue: 63),
  617.   (red: 55; green: 31; blue: 63),
  618.   (red: 63; green: 31; blue: 63),
  619.   (red: 63; green: 31; blue: 55),
  620.   (red: 63; green: 31; blue: 47),
  621.   (red: 63; green: 31; blue: 39),
  622.   (red: 63; green: 31; blue: 31),
  623.   (red: 63; green: 39; blue: 31),
  624.   (red: 63; green: 47; blue: 31),
  625.   (red: 63; green: 55; blue: 31),
  626.   (red: 63; green: 63; blue: 31),
  627.   (red: 55; green: 63; blue: 31),
  628.   (red: 47; green: 63; blue: 31),
  629.   (red: 39; green: 63; blue: 31),
  630.   (red: 31; green: 63; blue: 31),
  631.   (red: 31; green: 63; blue: 39),
  632.   (red: 31; green: 63; blue: 47),
  633.   (red: 31; green: 63; blue: 55),
  634.   (red: 31; green: 63; blue: 63),
  635.   (red: 31; green: 55; blue: 63),
  636.   (red: 31; green: 47; blue: 63),
  637.   (red: 31; green: 39; blue: 63),
  638.   (red: 45; green: 45; blue: 63),
  639.   (red: 49; green: 45; blue: 63),
  640.   (red: 54; green: 45; blue: 63),
  641.   (red: 58; green: 45; blue: 63),
  642.   (red: 63; green: 45; blue: 63),
  643.   (red: 63; green: 45; blue: 58),
  644.   (red: 63; green: 45; blue: 54),
  645.   (red: 63; green: 45; blue: 49),
  646.   (red: 63; green: 45; blue: 45),
  647.   (red: 63; green: 49; blue: 45),
  648.   (red: 63; green: 54; blue: 45),
  649.   (red: 63; green: 58; blue: 45),
  650.   (red: 63; green: 63; blue: 45),
  651.   (red: 58; green: 63; blue: 45),
  652.   (red: 54; green: 63; blue: 45),
  653.   (red: 49; green: 63; blue: 45),
  654.   (red: 45; green: 63; blue: 45),
  655.   (red: 45; green: 63; blue: 49),
  656.   (red: 45; green: 63; blue: 54),
  657.   (red: 45; green: 63; blue: 58),
  658.   (red: 45; green: 63; blue: 63),
  659.   (red: 45; green: 58; blue: 63),
  660.   (red: 45; green: 54; blue: 63),
  661.   (red: 45; green: 49; blue: 63),
  662.   (red:  0; green:  0; blue: 28),
  663.   (red:  7; green:  0; blue: 28),
  664.   (red: 14; green:  0; blue: 28),
  665.   (red: 21; green:  0; blue: 28),
  666.   (red: 28; green:  0; blue: 28),
  667.   (red: 28; green:  0; blue: 21),
  668.   (red: 28; green:  0; blue: 14),
  669.   (red: 28; green:  0; blue:  7),
  670.   (red: 28; green:  0; blue:  0),
  671.   (red: 28; green:  7; blue:  0),
  672.   (red: 28; green: 14; blue:  0),
  673.   (red: 28; green: 21; blue:  0),
  674.   (red: 28; green: 28; blue:  0),
  675.   (red: 21; green: 28; blue:  0),
  676.   (red: 14; green: 28; blue:  0),
  677.   (red:  7; green: 28; blue:  0),
  678.   (red:  0; green: 28; blue:  0),
  679.   (red:  0; green: 28; blue:  7),
  680.   (red:  0; green: 28; blue: 14),
  681.   (red:  0; green: 28; blue: 21),
  682.   (red:  0; green: 28; blue: 28),
  683.   (red:  0; green: 21; blue: 28),
  684.   (red:  0; green: 14; blue: 28),
  685.   (red:  0; green:  7; blue: 28),
  686.   (red: 14; green: 14; blue: 28),
  687.   (red: 17; green: 14; blue: 28),
  688.   (red: 21; green: 14; blue: 28),
  689.   (red: 24; green: 14; blue: 28),
  690.   (red: 28; green: 14; blue: 28),
  691.   (red: 28; green: 14; blue: 24),
  692.   (red: 28; green: 14; blue: 21),
  693.   (red: 28; green: 14; blue: 17),
  694.   (red: 28; green: 14; blue: 14),
  695.   (red: 28; green: 17; blue: 14),
  696.   (red: 28; green: 21; blue: 14),
  697.   (red: 28; green: 24; blue: 14),
  698.   (red: 28; green: 28; blue: 14),
  699.   (red: 24; green: 28; blue: 14),
  700.   (red: 21; green: 28; blue: 14),
  701.   (red: 17; green: 28; blue: 14),
  702.   (red: 14; green: 28; blue: 14),
  703.   (red: 14; green: 28; blue: 17),
  704.   (red: 14; green: 28; blue: 21),
  705.   (red: 14; green: 28; blue: 24),
  706.   (red: 14; green: 28; blue: 28),
  707.   (red: 14; green: 24; blue: 28),
  708.   (red: 14; green: 21; blue: 28),
  709.   (red: 14; green: 17; blue: 28),
  710.   (red: 20; green: 20; blue: 28),
  711.   (red: 22; green: 20; blue: 28),
  712.   (red: 24; green: 20; blue: 28),
  713.   (red: 26; green: 20; blue: 28),
  714.   (red: 28; green: 20; blue: 28),
  715.   (red: 28; green: 20; blue: 26),
  716.   (red: 28; green: 20; blue: 24),
  717.   (red: 28; green: 20; blue: 22),
  718.   (red: 28; green: 20; blue: 20),
  719.   (red: 28; green: 22; blue: 20),
  720.   (red: 28; green: 24; blue: 20),
  721.   (red: 28; green: 26; blue: 20),
  722.   (red: 28; green: 28; blue: 20),
  723.   (red: 26; green: 28; blue: 20),
  724.   (red: 24; green: 28; blue: 20),
  725.   (red: 22; green: 28; blue: 20),
  726.   (red: 20; green: 28; blue: 20),
  727.   (red: 20; green: 28; blue: 22),
  728.   (red: 20; green: 28; blue: 24),
  729.   (red: 20; green: 28; blue: 26),
  730.   (red: 20; green: 28; blue: 28),
  731.   (red: 20; green: 26; blue: 28),
  732.   (red: 20; green: 24; blue: 28),
  733.   (red: 20; green: 22; blue: 28),
  734.   (red:  0; green:  0; blue: 16),
  735.   (red:  4; green:  0; blue: 16),
  736.   (red:  8; green:  0; blue: 16),
  737.   (red: 12; green:  0; blue: 16),
  738.   (red: 16; green:  0; blue: 16),
  739.   (red: 16; green:  0; blue: 12),
  740.   (red: 16; green:  0; blue:  8),
  741.   (red: 16; green:  0; blue:  4),
  742.   (red: 16; green:  0; blue:  0),
  743.   (red: 16; green:  4; blue:  0),
  744.   (red: 16; green:  8; blue:  0),
  745.   (red: 16; green: 12; blue:  0),
  746.   (red: 16; green: 16; blue:  0),
  747.   (red: 12; green: 16; blue:  0),
  748.   (red:  8; green: 16; blue:  0),
  749.   (red:  4; green: 16; blue:  0),
  750.   (red:  0; green: 16; blue:  0),
  751.   (red:  0; green: 16; blue:  4),
  752.   (red:  0; green: 16; blue:  8),
  753.   (red:  0; green: 16; blue: 12),
  754.   (red:  0; green: 16; blue: 16),
  755.   (red:  0; green: 12; blue: 16),
  756.   (red:  0; green:  8; blue: 16),
  757.   (red:  0; green:  4; blue: 16),
  758.   (red:  8; green:  8; blue: 16),
  759.   (red: 10; green:  8; blue: 16),
  760.   (red: 12; green:  8; blue: 16),
  761.   (red: 14; green:  8; blue: 16),
  762.   (red: 16; green:  8; blue: 16),
  763.   (red: 16; green:  8; blue: 14),
  764.   (red: 16; green:  8; blue: 12),
  765.   (red: 16; green:  8; blue: 10),
  766.   (red: 16; green:  8; blue:  8),
  767.   (red: 16; green: 10; blue:  8),
  768.   (red: 16; green: 12; blue:  8),
  769.   (red: 16; green: 14; blue:  8),
  770.   (red: 16; green: 16; blue:  8),
  771.   (red: 14; green: 16; blue:  8),
  772.   (red: 12; green: 16; blue:  8),
  773.   (red: 10; green: 16; blue:  8),
  774.   (red:  8; green: 16; blue:  8),
  775.   (red:  8; green: 16; blue: 10),
  776.   (red:  8; green: 16; blue: 12),
  777.   (red:  8; green: 16; blue: 14),
  778.   (red:  8; green: 16; blue: 16),
  779.   (red:  8; green: 14; blue: 16),
  780.   (red:  8; green: 12; blue: 16),
  781.   (red:  8; green: 10; blue: 16),
  782.   (red: 11; green: 11; blue: 16),
  783.   (red: 12; green: 11; blue: 16),
  784.   (red: 13; green: 11; blue: 16),
  785.   (red: 15; green: 11; blue: 16),
  786.   (red: 16; green: 11; blue: 16),
  787.   (red: 16; green: 11; blue: 15),
  788.   (red: 16; green: 11; blue: 13),
  789.   (red: 16; green: 11; blue: 12),
  790.   (red: 16; green: 11; blue: 11),
  791.   (red: 16; green: 12; blue: 11),
  792.   (red: 16; green: 13; blue: 11),
  793.   (red: 16; green: 15; blue: 11),
  794.   (red: 16; green: 16; blue: 11),
  795.   (red: 15; green: 16; blue: 11),
  796.   (red: 13; green: 16; blue: 11),
  797.   (red: 12; green: 16; blue: 11),
  798.   (red: 11; green: 16; blue: 11),
  799.   (red: 11; green: 16; blue: 12),
  800.   (red: 11; green: 16; blue: 13),
  801.   (red: 11; green: 16; blue: 15),
  802.   (red: 11; green: 16; blue: 16),
  803.   (red: 11; green: 15; blue: 16),
  804.   (red: 11; green: 13; blue: 16),
  805.   (red: 11; green: 12; blue: 16),
  806.   (red:  0; green:  0; blue:  0),
  807.   (red:  0; green:  0; blue:  0),
  808.   (red:  0; green:  0; blue:  0),
  809.   (red:  0; green:  0; blue:  0),
  810.   (red:  0; green:  0; blue:  0),
  811.   (red:  0; green:  0; blue:  0),
  812.   (red:  0; green:  0; blue:  0),
  813.   (red: 63; green: 63; blue: 63)
  814.  );
  815.  
  816. VAR neue_Tabelle:ColorTable;
  817.     oldColor,newColor:PaletteEntry;
  818.     i,j,p:BYTE;
  819.     min:WORD;
  820.  
  821. BEGIN
  822.  IF (brightness<0) OR (brightness>100)
  823.   THEN BEGIN
  824.         Error:=Err_InvalidPercentage;
  825.         exit
  826.        END;
  827.  FOR i:=0 TO 255 DO 
  828.   BEGIN
  829.    {neue Farbe=alte, abgedunkelt auf "brightness" Prozent:}
  830.    newColor.red  :=default_Farben[i].red  * brightness DIV 100;
  831.    newColor.green:=default_Farben[i].green* brightness DIV 100;
  832.    newColor.blue :=default_Farben[i].blue * brightness DIV 100;
  833.  
  834.    {nun fuer diese Farbe eine moeglichst gute Naeherung finden:}
  835.    min:=65535;
  836.    FOR j:=255 DOWNTO 0 DO
  837.     BEGIN
  838.      oldColor:=default_Farben[j];
  839.      ASM
  840.         MOV AL,newColor.red  {Farbdifferenz im Rotanteil berechnen:}
  841.         SUB AL,oldColor.red
  842.         JL @heller           {<0 bedeutet: neue Farbe waere heller!}
  843.         MOV DL,AL            {>=0, quadrieren (um Differenzquadrat }
  844.         MUL DL               {zu minmieren)                        }
  845.         MOV BX,AX            {Dieses Fehlerquadrat in BX speichern }
  846.         MOV AL,newColor.green  {dto. fuer gruenen Farbanteil...    }
  847.         SUB AL,oldColor.green
  848.         JL @heller
  849.         MOV DL,AL
  850.         MUL DL
  851.         ADD BX,AX
  852.         JC @heller           {(Uebertrag bedeutet sofortiges Ende) }
  853.         MOV AL,newColor.blue {...und fuer den blauen Anteil auch   }
  854.         SUB AL,oldColor.blue
  855.         JL @heller
  856.         MOV DL,AL
  857.         MUL DL
  858.         ADD AX,BX
  859.         JNC @fertig
  860.       @heller:               {hierher, wenn heller: maximale Abwei-}
  861.         MOV AX,0FFFFh        {ung zurueckgeben, da nur dunklere    }
  862.       @fertig:               {Farben gewuenscht sind!              }
  863.                              {Abweichungsmass steht nun in AX!     }
  864.  
  865.         CMP AX,min           {falls Abweichung kleiner als bisheri-}
  866.         JAE @noNewMin        {ges Minimum ist die Farbe j der neue }
  867.         MOV min,AX           {beste Naeherungswert: ihn selbst (in }
  868.         MOV AL,j             {min) und diese Farbe (in p) merken   }
  869.         MOV p,AL
  870.       @noNewMin:
  871.      END;
  872.  
  873.     END; {of FOR j}
  874.     neue_Tabelle[i]:=p  {p = bester Naeherungswert fuer "newColor" }
  875.   END;
  876.  MOVE(neue_Tabelle,@ShadowTab^,256); {Farbtabelle uebernehmen}
  877. END;
  878.  
  879.  
  880. {Nun folgen die Codestuecke, die Verwendung finden, um ein Sprite auf den}
  881. {Schirm zu bringen; die Schnittstelle ist fuer alle gleich:              }
  882. { in: CX    = Anzahl Bytes, die von...                                   }
  883. {     DS:SI = (Zeiger auf Quelladresse) nach...                          }
  884. {     ES:BX = (Zeiger auf Zieladresses) zu bringen sind;                 }
  885. {     DI    = Bitplane (0..3) (=X-Koordinate AND 3)                      }
  886. {     Die Bitmaske fuer den richtigen Schreibe-Planezugriff wurde bereits}
  887. {     gesetzt, eine evtl. noetige Leseplane dagegen nicht!               }
  888. {     Die Routinen koennen sicher sein, dass CX<>0 ist                   }
  889. {rem: Jede dieser Routinen MUSS EXAKT 16 Bytes lang und VOLL RELOKATIBEL }
  890. {     sein, sowie die Register BP,DS,ES unveraendert lassen!!!!!!!!!!!!! }
  891. {     Ausserdem muessen die einzelnen Routinen zur Unterscheidbarkeit in }
  892. {     ihren ersten zwei Bytes paarweise verschieden sein!                }
  893.  
  894. PROCEDURE Modus0; ASSEMBLER;
  895. {Modus 0 betrachtet die Farbe 0 als durchsichtig fuer den Hintergrund}
  896. ASM
  897.    INC CX
  898.    STC
  899.    SBB BX,SI
  900.  @L1:
  901.    LODSB
  902.    OR AL,AL
  903.    LOOPZ @L1
  904.    JCXZ @L2
  905.    MOV ES:[BX+SI],AL
  906.    JMP @L1 {short}
  907.  @L2:
  908. END;
  909.  
  910. PROCEDURE Modus1; ASSEMBLER;
  911. {Modus 1 schreibt die Daten sofort ohne weitere Untersuchung auf den Schirm}
  912. ASM
  913.    MOV DI,BX
  914.    REP MOVSB
  915.    JMP @L3
  916.    NOP          {10 Bytes Platzhalter}
  917.    NOP
  918.    NOP
  919.    NOP
  920.    NOP
  921.    NOP
  922.    NOP
  923.    NOP
  924.    NOP
  925.    NOP
  926.  @L3:
  927. END;
  928.  
  929. PROCEDURE Modus2Work; ASSEMBLER;
  930. {Fortsetzung von Modus2 - all das, was nicht mehr in 16 Bytes unterzubringen}
  931. {war, kommt hierher}
  932. ASM
  933.    OUT DX,AX          {Lesezugriff auf passende Plane ermoeglichen}
  934.  
  935.    PUSH DS            {DS zeigt noch auf Spritedaten, muss aber auf}
  936.                       {Hintergrund zeigen!                         }
  937.    MOV AX,ES          {DS:SI := ES:DI  (Quellzeiger:=Zielzeiger)   }
  938.    MOV DS,AX
  939.    MOV SI,DI
  940.    MOV BX,OFFSET ShadowTab   {Zeiger auf Farbumsetztabelle setzen  }
  941.  
  942.  @L4:
  943.    LODSB              {Hintergrundfarbe holen...  }
  944.    SEGCS XLAT         {...mit Farbtabelle umsetzen}
  945.    STOSB              {...und auf aktueller Seite darstellen}
  946.    LOOP @L4
  947.  
  948.    POP DS
  949. END;
  950.  
  951. PROCEDURE Modus2; ASSEMBLER;
  952. {Modus 2 ist fuer "Schatten" und aehnliches gedacht: hierbei werden die }
  953. {eigentlichen Spritedaten ignoriert und stattdessen die Hintergrunddaten}
  954. {gelesen, die sich an der Spriteposition befinden und deren Farbwerte   }
  955. {gegen die der Farbtabelle "ShadowTab" ersetzt (um bspw. Schatten zu er-}
  956. {zeugen, muesste diese Tabelle zu jeder Farbe eine dunklere enthalten)  }
  957. ASM
  958.    MOV AX,DI          {Bitplane fuer Lesezugriff nach AX bringen}
  959.    MOV DI,BX          {fuer Stringbefehle die Zieladresse nach DI bringen}
  960.    MOV AH,AL          {Bitplane ins Highbyte bringen}
  961.    MOV AL,4
  962.    MOV DX,3CEh
  963.    MOV SI,OFFSET Modus2Work  {fieser Trick: "CALL Modus2Work" wuerde (da re-}
  964.    CALL SI                   {lativ codiert) zu falscher Adresse verzweigen!}
  965. END;
  966.  
  967.  
  968. PROCEDURE Adressen; ASSEMBLER;
  969. {Tabelle der Startadressen der 3 Routinen im Codesegment}
  970. ASM
  971.    DW OFFSET Modus0
  972.    DW OFFSET Modus1
  973.    DW OFFSET Modus2
  974. END;
  975.  
  976.  
  977. PROCEDURE GADR; ASSEMBLER;
  978. {Tabelle der Grafikzeilen-Startadressen (Offset-Anteil)}
  979. ASM
  980.    DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
  981.    DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
  982.    DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
  983.    DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
  984.    DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
  985.    DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
  986.    DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
  987.    DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
  988.    DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
  989.    DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
  990.    DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
  991.    DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
  992.    DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
  993.    DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
  994.    DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
  995.    DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
  996.    DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
  997.    DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
  998.    DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
  999.    DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
  1000.    DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
  1001.    DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
  1002.    DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
  1003.    DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
  1004.    DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
  1005. END;
  1006.  
  1007.  
  1008. FUNCTION AT:BOOLEAN;
  1009. { in: - }
  1010. {out: TRUE/FALSE, wenn die Maschine (mindestens) ein AT ist}
  1011. BEGIN
  1012.  AT:=MEM[$F000:$FFFE]=$FC
  1013. END;
  1014.  
  1015.  
  1016. PROCEDURE SetCycleTime(milliseconds:WORD);
  1017. { in: Mindestzeit eines Animationszyklus in Millisekunden}
  1018. {out: CycleTime := dieser Wert in Mikrosekunden}
  1019. {     TimeFlag  := $80}
  1020. {rem: Fuer den ersten Animationszyklus nach Aufruf dieser Routine}
  1021. {     gilt wg. TimeFlag:=$80 die Zeitbedingung noch nicht!       }
  1022. {     Schaltet der Benutzer (durch Angabe von milliseconds=0) die}
  1023. {     Zeitueberwachung explizit ab, so wird das durch IsAT:=$80, }
  1024. {     d.h.: "Rechner ist ein PC" vorgetaeuscht. Sonst ist IsAT=0 }
  1025. BEGIN
  1026.  TimeFlag:=$80;
  1027.  CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
  1028.  IF (milliseconds<>0) AND AT
  1029.   THEN IsAT:=0     {ja, Zeitueberwachung soll benutzt werden  }
  1030.   ELSE IsAT:=$80   {nein, keine moeglich oder nicht gewuenscht}
  1031. END;
  1032.  
  1033. PROCEDURE SetSpriteCycle(nr,len:WORD);
  1034. { in: nr  = Spriteladenummer des ersten Sprites des Zyklus      }
  1035. {     len = Laenge des zu definierenden Spritezyklus            }
  1036. {out: NextSprite[nr] bis NextSprite[nr+len-1] wurden so gesetzt,}
  1037. {     dass sie im Ring aufeinander zeigen, d.h.: sie bilden     }
  1038. {     einen Spritezyklus}
  1039. {rem: Soll der Zyklus aus nicht direkt aufeinanderfolgenden     }
  1040. {     (physikalischen) Sprites gebildet werden, so muessen die  }
  1041. {     entsprechenden Eintraege in NextSprite[] manuell gemacht  }
  1042. {     werden }
  1043. {     Diese Routine verwendet SpriteLADEnummern!}
  1044. VAR i:WORD;
  1045. BEGIN
  1046.  IF (nr<1) OR (nr+len-1>LoadMAX)
  1047.   THEN Error:=Err_InvalidSpriteLoadNumber
  1048.   ELSE BEGIN
  1049.         FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
  1050.         NextSprite[PRED(nr+len)]:=nr  {letztes Sprite zeigt auf erstes}
  1051.        END;
  1052. END;
  1053.  
  1054.  
  1055. FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
  1056. { in: (x1,y1) = linke obere Ecke des zu sichernden Bildausschnittes        }
  1057. {     (x2,y2) = rechte untere Ecke dazu (alles virtuelle Koordinaten!)     }
  1058. {     pa      = Grafikseite, von der der Ausschnitt zu sichern ist (0..2)  }
  1059. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke             }
  1060. {out: Zeiger auf Heapbereich, der den kopierten Bildausschnitt enthaelt    }
  1061. {     left_cut= evtl. noetiger linker Cutoff des Bildausschnittes (gibt an,}
  1062. {               um wieviel Punkte der Ausschnitt links ausserhalb des Bild-}
  1063. {               schirm ragte)                                              }
  1064. {     righ_cut,top_cut,bottom_cut = dto., fuer andere Raender              }
  1065. {     was_cut = TRUE/FALSE, falls ein zurechtstutzen des Bildausschnittes  }
  1066. {               noetig war/nicht noetig war                                }
  1067. {rem: Der benoetigte Speicher wird von der Routine automatisch reserviert  }
  1068. {     Sollte dies nicht moeglich sein (oder liegt der Bildausschnitt gaenz-}
  1069. {     lich ausserhalb des sichtbaren Bereichs), so wird NIL zurueckgegeben!}
  1070. {     Nur wenn "was_cut" TRUE ist, sind die Werte der globalen "..._cut"   }
  1071. {     Variablen <>0 gesetzt worden, d.h.: ist der Ausschnitt _ganz_ ausser-}
  1072. {     halb des Bildes (also zurueckgegebener Zeiger=NIL), dann liefert die }
  1073. {     Routine trotzdem "was_cut"=FALSE!}
  1074. VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
  1075.     p:POINTER;
  1076. BEGIN
  1077.  was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
  1078.  dec(x1,StartVirtualX);   {Bildschirmkoordinaten berechnen}
  1079.  dec(y1,StartVirtualY);
  1080.  IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
  1081.   THEN BEGIN  {Bildausschnitt nicht auf dem Bildschirm}
  1082.         GetImage:=NIL;
  1083.         exit
  1084.        END;
  1085.  {Ausschnitt auf Bildschirm zurechtklippen:}
  1086.  IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
  1087.  IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
  1088.  IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
  1089.  IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
  1090.  
  1091.  breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
  1092.  len:=breite*hoehe+2*2; {1 Pixel=1 Byte; dazu: 2 Woerter fuer breite & hoehe}
  1093.  IF len>MaxAvail
  1094.   THEN BEGIN
  1095.         Error:=Err_NotEnoughMemory;
  1096.         GetImage:=NIL;
  1097.         exit
  1098.        END;
  1099.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)  {Seitennummer muss 0..2 sein}
  1100.   THEN BEGIN
  1101.         Error:=Err_InvalidPageNumber;
  1102.         GetImage:=NIL;
  1103.         exit
  1104.        END
  1105.   ELSE SegmAdr:=Segment_Adr[pa];
  1106.  GetMem(p,len);         {Speicher auf dem Heap besorgen}
  1107.  ASM
  1108.     CLD
  1109.     LES DI,p        {ES:DI = Zeiger auf den besorgten Speicher}
  1110.     MOV AX,breite
  1111.     STOSW           {Breite zuerst ablegen...}
  1112.     MOV AX,hoehe
  1113.     STOSW           {...gefolgt von der Hoehe, danach dann die Daten}
  1114.  
  1115.     MOV BX,AX       {BX:=hoehe (fuer spaeter) }
  1116.     MOV SI,y1
  1117.     SHL SI,1
  1118.     MOV SI,CS:[OFFSET gadr + SI]   {SI:=y1*LINESIZE}
  1119.     MOV AX,x1
  1120.     MOV DL,AL
  1121.     SHR AX,1
  1122.     SHR AX,1
  1123.     ADD SI,AX       {SI:=Offsetanteil der Startadresse}
  1124.     MOV StartAdr,SI
  1125.     MOV actualAdr,SI
  1126.     AND DL,3
  1127.     MOV AH,DL
  1128.     MOV AL,4
  1129.     MOV DX,3CEh
  1130.     OUT DX,AX       {Startplane anwaehlen}
  1131.     MOV DS,SegmAdr
  1132.  
  1133.     {DS:SI = Zeiger auf erstes zu speicherndes Byte; ES:DI = Zieladr. dafuer}
  1134.     {AH = Startplane, AL = 4, BX = abzuarbeitende Zeilenanzahl}
  1135.  
  1136.     MOV DX,breite
  1137.     ADD DX,3
  1138.     SHR DX,1
  1139.     SHR DX,1        {DX = Anzahl zu sichernde Bytes je Zeile}
  1140.  
  1141.   @L1:
  1142.     MOV CX,DX       {Daten einer Zeile abspeichern}
  1143.     REP MOVSB
  1144.     MOV SI,actualAdr  {Quellzeiger um 1 Grafikzeile weitersetzen}
  1145.     ADD SI,LINESIZE
  1146.     MOV actualAdr,SI
  1147.     DEC BX          {Zeilenzaehler verringern}
  1148.     JNE @L1
  1149.  
  1150.     INC AH          {naechste Plane anwaehlen}
  1151.     CMP AH,4
  1152.     JNE @nowrap1    {wrap in den Bitplanes bedeutet: Startadresse}
  1153.     MOV AH,0        {um 1 Adresse weitersetzen! }
  1154.     INC StartAdr
  1155.   @nowrap1:
  1156.     MOV DX,3CEh
  1157.     OUT DX,AX
  1158.     MOV BX,hoehe
  1159.     MOV DX,breite
  1160.     INC DX
  1161.     INC DX
  1162.     SHR DX,1
  1163.     SHR DX,1
  1164.     MOV SI,StartAdr
  1165.     MOV actualAdr,SI
  1166.  
  1167.   @L2:
  1168.     MOV CX,DX
  1169.     REP MOVSB
  1170.     MOV SI,actualAdr
  1171.     ADD SI,LINESIZE
  1172.     MOV actualAdr,SI
  1173.     DEC BX
  1174.     JNE @L2
  1175.  
  1176.     INC AH
  1177.     CMP AH,4
  1178.     JNE @nowrap2
  1179.     MOV AH,0
  1180.     INC StartAdr
  1181.   @nowrap2:
  1182.     MOV DX,3CEh
  1183.     OUT DX,AX
  1184.     MOV BX,hoehe
  1185.     MOV DX,breite
  1186.     INC DX
  1187.     SHR DX,1
  1188.     SHR DX,1
  1189.     MOV SI,StartAdr
  1190.     MOV actualAdr,SI
  1191.  
  1192.   @L3:
  1193.     MOV CX,DX
  1194.     REP MOVSB
  1195.     MOV SI,actualAdr
  1196.     ADD SI,LINESIZE
  1197.     MOV actualAdr,SI
  1198.     DEC BX
  1199.     JNE @L3
  1200.  
  1201.     INC AH
  1202.     CMP AH,4
  1203.     JNE @nowrap3
  1204.     MOV AH,0
  1205.     INC StartAdr
  1206.   @nowrap3:
  1207.     MOV DX,3CEh
  1208.     OUT DX,AX
  1209.     MOV BX,hoehe
  1210.     MOV DX,breite
  1211.     SHR DX,1
  1212.     SHR DX,1
  1213.     MOV SI,StartAdr
  1214.     MOV actualAdr,SI
  1215.  
  1216.   @L4:
  1217.     MOV CX,DX
  1218.     REP MOVSB
  1219.     MOV SI,actualAdr
  1220.     ADD SI,LINESIZE
  1221.     MOV actualAdr,SI
  1222.     DEC BX
  1223.     JNE @L4
  1224.  
  1225.     MOV AX,SEG @DATA
  1226.     MOV DS,AX
  1227.  END;
  1228.  GetImage:=p
  1229. END;
  1230.  
  1231. PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
  1232. { in: (x,y) = linke obere Ecke des Zieles (in virtuellen Koordinaten)   }
  1233. {     p     = Zeiger auf (durch GetImage erstellten) Bildausschnitt     }
  1234. {     pa    = Grafikseite, in die der Bildausschnitt kopiert werden soll}
  1235. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke          }
  1236. {out: - }
  1237. {rem: Der Bildausschnitt wurde zur Bildschirmdarstellung zurechtgeklippt}
  1238. {     Bei Uebergabe von NIL als Zeiger stellt die Routine gar nicht dar;}
  1239. {     Dies hilft fuer eine direkte Uebernahme der von GetImage gelie-   }
  1240. {     ferten Werte!                                                     }
  1241. VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
  1242.     licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
  1243.     licutoff,temp:INTEGER;
  1244. BEGIN
  1245.  IF p=NIL THEN exit;
  1246.  dec(x,StartVirtualX);   {Bildschirmkoordinaten berechnen}
  1247.  dec(y,StartVirtualY);
  1248.  IF (x>XMAX) or (y>YMAX) THEN exit;
  1249.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  1250.   THEN BEGIN
  1251.         Error:=Err_InvalidPageNumber;
  1252.         exit
  1253.        END
  1254.   ELSE SegmAdr:=Segment_Adr[pa];
  1255.  breite:=MEMW[SEG(p^):OFS(p^)];
  1256.  hoehe :=MEMW[SEG(p^):OFS(p^)+2];
  1257.  IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
  1258.  IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
  1259.         ELSE licutoff:=0;
  1260.  IF y<0 THEN BEGIN
  1261.               topcut:=-y;
  1262.               y:=0
  1263.              END
  1264.         ELSE topcut:=0;
  1265.  
  1266.  breite1:=(breite + 3) shr 2;  {Breite einer Zeile fuer die erste, zweite,}
  1267.  breite2:=(breite + 2) shr 2;  {dritte und vierte Bitplane}
  1268.  breite3:=(breite + 1) shr 2;
  1269.  breite4:=(breite + 0) shr 2;
  1270.  
  1271.  {Anfangsadressen der 4 Bitplanes berechnen; dabei evtl. linken cutoff mit}
  1272.  {einbeziehen (plus 4 Bytes zum ueberspringen von "breite" und "hoehe"    }
  1273.  licut_div4:=licutoff shr 2;
  1274.  pl_adr1:=4 +licut_div4 +topcut*breite1;
  1275.  pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
  1276.  pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
  1277.  pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
  1278.  
  1279.  {licutoff mod 4 gibt an, in welcher Reihenfolge die Punkte aus dem Heap }
  1280.  {gelesen werden muessen: 0 = Planereihenfolge (1,2,3,4); 1=(2,3,4,1);   }
  1281.  {2=(3,4,1,2); 3=(4,1,2,3); zu beachten ist, dass die Breiten der einzel-}
  1282.  {nen Bitplanetabellen natuerlich mit diesen verbunden bleibt und deshalb}
  1283.  {mitgetauscht werden muss!}
  1284.  ASM
  1285.     CLD
  1286.     MOV AX,licutoff
  1287.     AND AL,3
  1288.     OR AL,AL
  1289.     JE @no_exchange
  1290.     CMP AL,1
  1291.     JNE @L10
  1292.  
  1293.     MOV AX,pl_adr2     {Verschiebung um 1 Bit: }
  1294.     MOV BX,pl_adr3     {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
  1295.     MOV CX,pl_adr4
  1296.     MOV DX,pl_adr1     {wrap-around, deshalb: Adresse um 1 erhoehen, was  }
  1297.     INC DX             {einer Weitersetzung um 4 Bildpunkte entspricht    }
  1298.     MOV pl_adr1,AX     {(z.B.: Pixel (1,5,9,...),(2,6,10,...),(3,7,11,...)}
  1299.     MOV pl_adr2,BX     {und (0,4,8,...); letztere Bitplane wird um 1 Byte }
  1300.     MOV pl_adr3,CX     {weitergesetzt: liefert (richtige) (4,8,12,...)    }
  1301.     MOV pl_adr4,DX     {Folge (Planes abwechselnd von oben nach unten lesen!}
  1302.     MOV AX,breite2     {Jetzt Planebreiten: }
  1303.     MOV BX,breite3     {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
  1304.     MOV CX,breite4
  1305.     MOV DX,breite1
  1306.     JMP @store
  1307.  
  1308.   @L10:
  1309.     CMP AL,2
  1310.     JNE @L20
  1311.  
  1312.     MOV AX,pl_adr3     {Verschiebung um 2 Bit: }
  1313.     MOV BX,pl_adr4     {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
  1314.     MOV CX,pl_adr1
  1315.     INC CX
  1316.     MOV DX,pl_adr2
  1317.     INC DX
  1318.     MOV pl_adr1,AX
  1319.     MOV pl_adr2,BX
  1320.     MOV pl_adr3,CX
  1321.     MOV pl_adr4,DX
  1322.     MOV AX,breite3     {dto. fuer Planebreiten: }
  1323.     MOV BX,breite4     {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
  1324.     MOV CX,breite1
  1325.     MOV DX,breite2
  1326.     JMP @store
  1327.   @L20:
  1328.     MOV AX,pl_adr4     {Verschiebung um 3 Bit: }
  1329.     MOV BX,pl_adr1     {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
  1330.     INC BX
  1331.     MOV CX,pl_adr2
  1332.     INC CX
  1333.     MOV DX,pl_adr3
  1334.     INC DX
  1335.     MOV pl_adr1,AX
  1336.     MOV pl_adr2,BX
  1337.     MOV pl_adr3,CX
  1338.     MOV pl_adr4,DX
  1339.     MOV AX,breite4     {dto. fuer Planebreiten: }
  1340.     MOV BX,breite1     {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
  1341.     MOV CX,breite2
  1342.     MOV DX,breite3
  1343.   @store:
  1344.     MOV breite1,AX
  1345.     MOV breite2,BX
  1346.     MOV breite3,CX
  1347.     MOV breite4,DX
  1348.  
  1349.   @no_exchange:        {jetzt gilt: (pl_adr?,breite?) enthalten die Source-}
  1350.                        {Bitplanes/-breiten in der richtigen Reihenfolge    }
  1351.  
  1352.     MOV AX,topcut
  1353.     SUB hoehe,AX       {Hoehe um evtl. oberen cutoff korrigieren}
  1354.     MOV AX,licutoff
  1355.     SUB breite,AX      {dto. fuer Breite und linken cutoff}
  1356.  
  1357.     MOV AX,x           {falls Ausschnitt ueber rechten Bildschirmrand}
  1358.     ADD AX,breite      {ragen wuerde: rechten cutoff bestimmen       }
  1359.     SUB AX,XMAX+1
  1360.     JLE @no_recutoff
  1361.     SUB breite,AX      {AX Punkte rechts abschneiden}
  1362.   @no_recutoff:
  1363.  
  1364.     MOV AX,y           {genau dasselbe fuer unteren Bildschirmrand}
  1365.     ADD AX,hoehe
  1366.     SUB AX,YMAX+1
  1367.     JLE @no_bocutoff
  1368.     SUB hoehe,AX       {AX Zeilen unten abschneiden}
  1369.   @no_bocutoff:
  1370.  
  1371.  
  1372.     LDS SI,p
  1373.     ADD pl_adr2,SI       {Offsetanteil des Zeigers zu den Planeadr. addieren}
  1374.     ADD pl_adr3,SI
  1375.     ADD pl_adr4,SI
  1376.  
  1377.     ADD SI,pl_adr1    {breite,hoehe und Teile oberhalb des Bildschirms}
  1378.     MOV ES,SegmAdr
  1379.  
  1380.     MOV DI,y
  1381.     SHL DI,1
  1382.     MOV DI,CS:[OFFSET gadr + DI]  {DI:=y*LINESIZE}
  1383.     MOV AX,x
  1384.     MOV BL,AL
  1385.     SHR AX,1
  1386.     SHR AX,1
  1387.     ADD DI,AX         {DI:=y*LINESIZE +(x DIV 4)}
  1388.     MOV StartAdr,DI
  1389.     MOV actualAdr,DI
  1390.  
  1391.     AND BX,3          {Startplane:=x mod 3}
  1392.     MOV AH,CS:[OFFSET CS_TranslateTab + BX]
  1393.     MOV AL,2
  1394.     MOV DX,3C4h
  1395.     OUT DX,AX         {als Schreibplane anwaehlen}
  1396.  
  1397.     MOV DX,hoehe
  1398.     MOV DI,actualAdr
  1399.  
  1400.     {DS:SI = Zeiger auf Daten, ES:DI = Zieladresse dafuer auf dem Schirm,}
  1401.     {AH = Bitmaske fuer Zugriff, AL = 2 }
  1402.     MOV BX,breite
  1403.     ADD BX,3
  1404.     SHR BX,1
  1405.     SHR BX,1
  1406.     mov cx,bx
  1407.   @L1:
  1408.     push si
  1409.     REP MOVSB
  1410.     pop si
  1411.     mov cx,bx
  1412.     add si,breite1
  1413.     MOV DI,actualAdr
  1414.     ADD DI,LINESIZE
  1415.     MOV actualAdr,DI
  1416.     DEC DX
  1417.     JNE @L1
  1418.  
  1419.  
  1420.     SHL AH,1          {naechste Bitplane anwaehlen; bei einem wrap von}
  1421.     CMP AH,16         {Bitplane 3 zu Bitplane 0 muss dabei die Start- }
  1422.     JNE @nowrap1      {adresse um 1 Byte weitergesetzt werden         }
  1423.     MOV AH,1
  1424.     INC StartAdr
  1425.   @nowrap1:
  1426.     MOV DX,3C4h
  1427.     OUT DX,AX
  1428.     MOV SI,pl_adr2
  1429.     MOV DI,StartAdr
  1430.     MOV actualAdr,DI
  1431.     MOV DX,hoehe
  1432.     MOV BX,breite
  1433.     INC BX
  1434.     INC BX
  1435.     SHR BX,1
  1436.     SHR BX,1
  1437.     mov cx,bx
  1438.   @L2:
  1439.     push si
  1440.     REP MOVSB
  1441.     pop si
  1442.     mov cx,bx
  1443.     add si,breite2
  1444.     MOV DI,actualAdr
  1445.     ADD DI,LINESIZE
  1446.     MOV actualAdr,DI
  1447.     DEC DX
  1448.     JNE @L2
  1449.  
  1450.  
  1451.     SHL AH,1
  1452.     CMP AH,16
  1453.     JNE @nowrap2
  1454.     MOV AH,1
  1455.     INC StartAdr
  1456.   @nowrap2:
  1457.     MOV DX,3C4h
  1458.     OUT DX,AX
  1459.     MOV SI,pl_adr3
  1460.     MOV DI,StartAdr
  1461.     MOV actualAdr,DI
  1462.     MOV DX,hoehe
  1463.     MOV BX,breite
  1464.     INC BX
  1465.     SHR BX,1
  1466.     SHR BX,1
  1467.     mov cx,bx
  1468.   @L3:
  1469.     push si
  1470.     REP MOVSB
  1471.     pop si
  1472.     mov cx,bx
  1473.     add si,breite3
  1474.     MOV DI,actualAdr
  1475.     ADD DI,LINESIZE
  1476.     MOV actualAdr,DI
  1477.     DEC DX
  1478.     JNE @L3
  1479.  
  1480.  
  1481.     SHL AH,1
  1482.     CMP AH,16
  1483.     JNE @nowrap3
  1484.     MOV AH,1
  1485.     INC StartAdr
  1486.   @nowrap3:
  1487.     MOV DX,3C4h
  1488.     OUT DX,AX
  1489.     MOV SI,pl_adr4
  1490.     MOV DI,StartAdr
  1491.     MOV actualAdr,DI
  1492.     MOV DX,hoehe
  1493.     MOV BX,breite
  1494.     SHR BX,1
  1495.     SHR BX,1
  1496.     mov cx,bx
  1497.   @L4:
  1498.     push si
  1499.     REP MOVSB
  1500.     pop si
  1501.     mov cx,bx
  1502.     add si,breite4
  1503.     MOV DI,actualAdr
  1504.     ADD DI,LINESIZE
  1505.     MOV actualAdr,DI
  1506.     DEC DX
  1507.     JNE @L4
  1508.  
  1509.     MOV AX,SEG @DATA
  1510.     MOV DS,AX
  1511.  END;
  1512.  
  1513. END;
  1514.  
  1515. PROCEDURE Screen(pa:BYTE);
  1516. { in: pa = anzuzeigende Bildschirmseite (0..3) }
  1517. {out: - }
  1518. {rem: Es wurde auf die Darstellung der Grafikseite pa umgeschaltet     }
  1519. {     Dabei wurde NICHT auf irgendwelche Retrace-Signale synchronisiert}
  1520. {     Sinnvoll sind nur die Seiten 0 oder 1, es findet aber keine      }
  1521. {     Ueberpruefung statt!}
  1522. BEGIN
  1523.  ASM
  1524.   MOV DX,$3D4                {CRT-Controller}
  1525.   MOV AL,$0D                 {LB-Startadress-Register}
  1526.   CLI                        {Darf keinenfalls unterbrochen werden!}
  1527.   OUT DX,AL
  1528.   INC DX
  1529.                              {Realisiere "AX:=Offset_Adr[pa]":}
  1530.   MOV BL,pa
  1531.   MOV SI,BX
  1532.   AND SI,3                   {Page-Wert *2 (da Worteintraege!)}
  1533.   SHL SI,1                   {dazu Startadresse des Feldes addieren}
  1534.   ADD SI,OFFSET Offset_Adr-StartIndex*2  {evtl. Verschiebung korrigieren}
  1535.   LODSW                      {und Wert holen}
  1536.   OUT DX,AL                  {LB der neuen Startadresse setzen}
  1537.   DEC DX
  1538.   MOV AL,$0C
  1539.   OUT DX,AL
  1540.   INC DX
  1541.   MOV AL,AH                  {HB der neuen Startadresse setzen}
  1542.   OUT DX,AL
  1543.   STI
  1544.  END;
  1545. END;
  1546.  
  1547. PROCEDURE InitGraph;
  1548. { in: PAGE = aktuelle Grafikseite}
  1549. {out: - }
  1550. {rem: Schaltet die VGA-Karte in den 320x200x256x4-Modus; ACHTUNG!    }
  1551. {     Dieser Modus ist verschieden vom Modus $13 der VGA!!!          }
  1552. {     Dabei wird auf die Darstellung der Seite 1-PAGE geschaltet     }
  1553. BEGIN
  1554. INLINE(
  1555.   $B8/$13/$00/ {0100: MOV    AX,0013 ;Mit BIOS Grafikmodus $13       }
  1556.   $CD/$10/     {0103: INT    10      ;(=320x200x256) setzen          }
  1557.   $BA/$C4/$03/ {0105: MOV    DX,03C4 ;Sequenzer ansteuern und dort   }
  1558.   $B0/$04/     {0108: MOV    AL,04   ;das Speichermodus-Register     }
  1559.   $EE/         {010A: OUT    DX,AL   ;auswaehlen                     }
  1560.   $42/         {010B: INC    DX      ;Dessen Daten ueber das zuge-   }
  1561.   $EC/         {010C: IN     AL,DX   ;hoerige Datenregister einlesen }
  1562.   $24/$F7/     {010D: AND    AL,F7   ;Bit 3:=0:4 Planes nicht chainen}
  1563.   $0C/$04/     {010F: OR     AL,04   ;Bit 2:=1:kein odd/even-Mechan. }
  1564.   $EE/         {0111: OUT    DX,AL   ;Neuen Wert wirksam machen      }
  1565.   $BA/$C4/$03/ {0112: MOV    DX,03C4 ;S.o.: Sequenzer-Register 2     }
  1566.   $B0/$02/     {0115: MOV    AL,02   ;(=Map-Maske)                   }
  1567.   $EE/         {0117: OUT    DX,AL   ;auswaehlen,...                 }
  1568.   $42/         {0118: INC    DX                                      }
  1569.   $B0/$0F/     {0119: MOV    AL,0F   ;...und Zugriff auf alle 4      }
  1570.   $EE/         {011B: OUT    DX,AL   ;Bitmaps erlauben               }
  1571.   $B8/$00/$A0/ {011C: MOV    AX,A000 ;Ab Segment $A000               }
  1572.   $8E/$C0/     {011F: MOV    ES,AX   ;$8000 logische Woerter=        }
  1573.   $29/$FF/     {0121: SUB    DI,DI   ;4*$8000 physikalische Woerter  }
  1574.   $89/$F8/     {0123: MOV    AX,DI   ;(wg. den 4 Bitplanes) auf 0    }
  1575.   $B9/$00/$80/ {0125: MOV    CX,8000 ;setzen                         }
  1576.   $FC/         {0128: CLD                                            }
  1577.   $F2/         {0129: REPNZ                                          }
  1578.   $AB/         {012A: STOSW                                          }
  1579.   $BA/$D4/$03/ {012B: MOV    DX,03D4 ;CRT-Controller ansteuern       }
  1580.   $B0/$14/     {012E: MOV    AL,14   ;Underline-location-Register    }
  1581.   $EE/         {0130: OUT    DX,AL   ;auswaehlen                     }
  1582.   $42/         {0131: INC    DX      ;Wert aus zugehoerigem          }
  1583.   $EC/         {0132: IN     AL,DX   ;Datenregister auslesen         }
  1584.   $24/$BF/     {0133: AND    AL,BF   ;Bit 6:=0: keine Doppelwort-    }
  1585.   $EE/         {0135: OUT    DX,AL   ;adressierung von Daten im Bild-}
  1586.   $4A/         {0136: DEC    DX      ;schirmspeicher durchfuehren    }
  1587.   $B0/$17/     {0137: MOV    AL,17   ;Mode-control-Register          }
  1588.   $EE/         {0139: OUT    DX,AL   ;auswaehlen                     }
  1589.   $42/         {013A: INC    DX                                      }
  1590.   $EC/         {013B: IN     AL,DX                                   }
  1591.   $0C/$40/     {013C: OR     AL,40   ;Bit 6:=1: Adressierung des     }
  1592.   $EE          {013E: OUT    DX,AL   ;Speichers=lineares Bitfeld     }
  1593.   );
  1594.  Screen(1-PAGE);  {sichtbar ist immer die nichtaktuelle Grafikseite}
  1595. END;
  1596.  
  1597.  
  1598. PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
  1599. { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
  1600. {     Color       = Farbe (0..255)             }
  1601. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke         }
  1602. {     pa          = Grafikseite, auf der gezeichnet werden soll (0..2) }
  1603. {out: - }
  1604. {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2)  }
  1605. {     in der Farbe COLOR gezeichnet; die Routine fuehrt dabei selber die   }
  1606. {     Umrechnung der angeg. Koordinaten in absolute Bildschirmkoordinaten  }
  1607. {     sowie evtl. notwendige Clipping-Schritte aus.                        }
  1608. {     Die Linie wird NICHT automatisch in den Hintergrund uebernommen,     }
  1609. {     d.h.: sie ist nur fuer einen Animationszyklus sichtbar (soll sie     }
  1610. {     permanent bleiben, so muss sie in den Hintergrund gezeichnet werden!)}
  1611. {     (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
  1612. {     zufuehren, da die gezeichnete Linie sonst sofort wieder verschwindet)}
  1613. CONST CodeLinks =$7;  {%0111}
  1614.       CodeRechts=$B;  {%1011}
  1615.       CodeOben  =$D;  {%1101}
  1616.       CodeUnten =$E;  {%1110}
  1617. BEGIN
  1618.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  1619.   THEN Error:=Err_InvalidPageNumber
  1620.   ELSE
  1621.   {zuerst Linie auf sichtbaren Bereich zurechtklippen; dazu Sutherland-}
  1622.   {Cohen-Algorithmus verwenden: 4 Bit-Code: links|rechts|oben|unten    }
  1623.   ASM
  1624.      CLD
  1625.      MOV CL,$F         {mit %1111 anfangen}
  1626.      MOV AX,x2
  1627.      SUB AX,StartVirtualX   {x2 in absolute Koordinaten umrechnen}
  1628.      MOV x2,AX
  1629.      OR AX,AX          {x2<0 ?}
  1630.      JL @GC1Punkt2     {ja, Flag fuer "Punkt links vom Fenster" belassen}
  1631.      AND CL,CodeLinks  {nein, Flag ruecksetzen}
  1632.    @GC1Punkt2:
  1633.      CMP AX,XMAX       {x2>XMAX ?}
  1634.      JG @GC2Punkt2     {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
  1635.      AND CL,CodeRechts {nein, Flag ruecksetzen}
  1636.    @GC2Punkt2:
  1637.      MOV AX,y2
  1638.      SUB AX,StartVirtualY   {y2 in absolute Koordinaten umrechnen}
  1639.      MOV y2,AX
  1640.      OR AX,AX          {y2<0 ?}
  1641.      JL @GC3Punkt2     {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
  1642.      AND CL,CodeOben   {nein, Flag ruecksetzen}
  1643.    @GC3Punkt2:
  1644.      CMP AX,YMAX       {y2>YMAX ?}
  1645.      JG @GC4Punkt2     {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
  1646.      AND CL,CodeUnten
  1647.    @GC4Punkt2:         {CL enthaelt jetzt den Gebietscode fuer Punkt 2}
  1648.  
  1649.      MOV AX,x1
  1650.      SUB AX,StartVirtualX   {x1 in absolute Koordinaten umrechnen}
  1651.      MOV x1,AX
  1652.      MOV AX,y1
  1653.      SUB AX,StartVirtualY   {y1 in absolute Koordinaten umrechnen}
  1654.      MOV y1,AX
  1655.  
  1656.    @Punkt1:
  1657.      MOV CH,$F         {mit %1111 anfangen}
  1658.      MOV AX,x1
  1659.      OR AX,AX          {x1<0 ?}
  1660.      JL @GC1Punkt1     {ja, Flag fuer "Punkt links vom Fenster" belassen}
  1661.      AND CH,CodeLinks  {nein, Flag ruecksetzen}
  1662.    @GC1Punkt1:
  1663.      CMP AX,XMAX       {x1>XMAX ?}
  1664.      JG @GC2Punkt1     {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
  1665.      AND CH,CodeRechts {nein, Flag ruecksetzen}
  1666.    @GC2Punkt1:
  1667.      MOV AX,y1
  1668.      OR AX,AX          {y1<0 ?}
  1669.      JL @GC3Punkt1     {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
  1670.      AND CH,CodeOben   {nein, Flag ruecksetzen}
  1671.    @GC3Punkt1:
  1672.      CMP AX,YMAX       {y1>YMAX ?}
  1673.      JG @GC4Punkt1     {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
  1674.      AND CH,CodeUnten
  1675.    @GC4Punkt1:         {CH enthaelt jetzt den Gebietscode fuer Punkt 1}
  1676.  
  1677.    {CL enthaelt den Gebietscode fuer Punkt 2, CH den fuer Punkt 1}
  1678.  
  1679.      MOV AX,CX
  1680.      AND AL,AH         {Code1 AND Code2 <>0 ?}
  1681.      JNZ @LineReady    {ja, Linie ganz ausserhalb des Windows}
  1682.      MOV AX,CX
  1683.      OR AL,AH          {Code1 OR Code2 =0 ?}
  1684.      JZ @DrawLine      {ja, Linie ganz innerhalb des Windows}
  1685.  
  1686.    {Nun eigentliches Clipping vornehmen: }
  1687.      MOV AX,CX
  1688.      OR AH,AH          {Code1 =0 ?}
  1689.      JNZ @CL3          {nein, alles ok}
  1690.      MOV AX,x1         {ja, Punkte vertauschen!}
  1691.      XCHG AX,x2
  1692.      MOV x1,AX
  1693.      MOV AX,y1
  1694.      XCHG AX,y2
  1695.      MOV y1,AX
  1696.      XCHG CL,CH
  1697.    @CL3:
  1698.      MOV AL,CH        {AL:=Code1}
  1699.      MOV BX,x2
  1700.      SUB BX,x1        {BX:=x2-x1}
  1701.      MOV SI,y2
  1702.      SUB SI,y1        {SI:=y2-y1}
  1703.      TEST AL,NOT CodeLinks     {Punkt1 links des Windows?}
  1704.      JZ @CL4                   {nein}
  1705.      {ja, neue Koordinaten berechnen: y1:=y1+(y2-y1)/(x2-x1)*(WindowX1-X1) }
  1706.      {und x1:=WindowX1   (dabei ist WindowX1 = 0) }
  1707.      XOR AX,AX
  1708.      XCHG AX,x1       {x1:=0}
  1709.      NEG AX           {AX:=-x1old}
  1710.      IMUL SI
  1711.      IDIV BX
  1712.      ADD y1,AX
  1713.      JMP @Punkt1
  1714.  
  1715.    @CL4:
  1716.      TEST AL,NOT CodeRechts    {Punkt1 rechts des Windows?}
  1717.      JZ @CL5                   {nein}
  1718.      {ja, berechne: y1:=y1+(y2-y1)/(x2-x1)*(WindowX2-X1), x1:=WindowX2 }
  1719.      { (wobei WindowX2=XMAX) }
  1720.      MOV AX,XMAX
  1721.      SUB AX,x1
  1722.      IMUL SI
  1723.      IDIV BX
  1724.      ADD y1,AX
  1725.      MOV x1,XMAX
  1726.      JMP @Punkt1
  1727.  
  1728.    @CL5:
  1729.      TEST AL,NOT CodeOben      {Punkt1 oberhalb des Windows?}
  1730.      JZ @CL6                   {nein}
  1731.      {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY1-y1), y1:=WindowY1 }
  1732.      { (wobei WindowY1=0) }
  1733.      XOR AX,AX
  1734.      XCHG AX,y1
  1735.      NEG AX
  1736.      IMUL BX
  1737.      IDIV SI
  1738.      ADD x1,AX
  1739.      JMP @Punkt1
  1740.  
  1741.    @CL6:
  1742.      TEST AL,NOT CodeUnten     {Punkt unterhalb des Windows?}
  1743.      JZ @Punkt1                {nein}
  1744.      {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY2-y1), y1:=WindowY2 }
  1745.      { (wobei WindowY2=YMAX) }
  1746.      MOV AX,YMAX
  1747.      SUB AX,y1
  1748.      IMUL BX
  1749.      IDIV SI
  1750.      ADD x1,AX
  1751.      MOV y1,YMAX
  1752.      JMP @Punkt1
  1753.  
  1754.    {Hier gilt: die beiden Punkte wurden auf den sichtbaren Bereich zurecht-}
  1755.    {gestutzt; sollte die Gerade keinen sichtbaren Teil besitzen, so wurde  }
  1756.    {direkt zu @LineReady verzweigt! }
  1757.    @DrawLine:
  1758.      PUSH BP
  1759.      MOV Steigung,0  {Flag zuruecksetzen}
  1760.      MOV CX,x2
  1761.      SUB CX,x1       {Punkt1 rechts von Punkt2 ?}
  1762.      JGE @posDX      {nein}
  1763.      NEG CX          {ja, Punkte vertauschen}
  1764.      MOV AX,x1
  1765.      XCHG AX,x2
  1766.      MOV x1,AX
  1767.      MOV AX,y1
  1768.      XCHG AX,y2
  1769.      MOV y1,AX
  1770.  
  1771.    @posDX:
  1772.      MOV DI,y1
  1773.      SHL DI,1
  1774.      MOV DI,CS:[OFFSET gadr + DI]   {DI:=y1*LINESIZE}
  1775.      MOV AX,x1
  1776.      MOV BL,AL
  1777.      SHR AX,1
  1778.      SHR AX,1
  1779.      ADD DI,AX       {DI:=y1*LINESIZE+(x1 DIV 4) }
  1780.  
  1781.      AND BX,3        {BX:=(x1 AND 4) }
  1782.      MOV DH,[OFFSET TranslateTab + BX]  {Maske fuer VRAM-Zugriff holen}
  1783.      MOV DL,2
  1784.  
  1785.      MOV BL,pa       {BH=0 -> BX=Zeichenseite}
  1786.      SHL BX,1
  1787.      ADD BX,OFFSET Segment_Adr -StartIndex*2
  1788.      MOV ES,[BX]
  1789.  
  1790.      {ES:DI=Zeiger auf Grafikadresse von Punkt1, DX=Zugriffsmaske dafuer}
  1791.      MOV SI,LINESIZE
  1792.      MOV BX,y2
  1793.      SUB BX,y1       {Punkt1 unterhalb von Punkt2 ?}
  1794.      JG @posDY       {nein}
  1795.      NEG BX          {ja, deltaY und Zeileninkrement negieren}
  1796.      NEG SI
  1797.  
  1798.    @posDY:
  1799.      CMP BX,CX       {deltaY>deltaX ?}
  1800.      JLE @flach      {nein: geringe Steigung, <=1 }
  1801.      XCHG BX,CX      {ja, deltas vertauschen und Flag setzen}
  1802.      MOV Steigung,1
  1803.  
  1804.    {Jetzt Bresenham-Parameter berechnen: 2*DY, 2*DY-DX, 2*(DY-DX) }
  1805.    @flach:
  1806.      SHL BX,1
  1807.      MOV DY_mal2,BX
  1808.      SUB BX,CX
  1809.      MOV BP,BX       {BP:=2*DY-DX}
  1810.      SUB BX,CX
  1811.      MOV DY_m_DX_mal2,BX
  1812.      INC CX          {CX:=Anzahl Pixel}
  1813.      MOV BL,Color
  1814.      MOV BH,1
  1815.      CMP Steigung,0  {steile Linie?}
  1816.      JNZ @high1      {ja}
  1817.  
  1818.    @low1:            {nein}
  1819.      MOV AX,3C4h
  1820.      XCHG AX,DX
  1821.      OUT DX,AX       {richtige Bitplane anwaehlen}
  1822.      MOV DX,AX       {Maske wieder nach DX retten}
  1823.      MOV AL,BL       {Farbe fuer Punkt holen}
  1824.      STOSB           {Punkt setzen}
  1825.      SHL DH,1        {Maske fuer naechsten Punkt berechnen    }
  1826.      CMP DH,16       {noch mit derselben Adresse ansprechbar? }
  1827.      JE @nextbyte1   {nein, Adr. muss(te) um 1 erhoeht werden }
  1828.      DEC DI          {ja, Erhoehung von DI rueckgängig machen }
  1829.    @low1b:
  1830.      OR BP,BP
  1831.      JGE @low2
  1832.      ADD BP,DY_mal2
  1833.      LOOP @low1
  1834.      JMP @raus
  1835.    @nextbyte1:
  1836.      MOV DH,BH       {Maske auf 1 zuruecksetzen}
  1837.      JMP @low1b      {Rest wie gehabt}
  1838.  
  1839.    @low2:
  1840.      ADD BP,DY_m_DX_mal2
  1841.      ADD DI,SI
  1842.      LOOP @low1
  1843.      JMP @raus
  1844.  
  1845.  
  1846.    @high1:
  1847.      MOV AX,3C4h
  1848.      XCHG AX,DX
  1849.      OUT DX,AX
  1850.      MOV DX,AX
  1851.      MOV AL,BL
  1852.    @high1b:
  1853.      OR BP,BP
  1854.      JGE @high2
  1855.      ADD BP,DY_mal2
  1856.      MOV ES:[DI],AL
  1857.      ADD DI,SI
  1858.      LOOP @high1b
  1859.      JMP @raus
  1860.  
  1861.    @high2:
  1862.      ADD BP,DY_m_DX_mal2
  1863.      SHL DH,1
  1864.      CMP DH,16
  1865.      JE @nextbyte2
  1866.      MOV ES:[DI],AL
  1867.      ADD DI,SI
  1868.      LOOP @high1
  1869.      JMP @raus
  1870.    @nextbyte2:
  1871.      MOV DH,BH
  1872.      STOSB
  1873.      ADD DI,SI
  1874.      LOOP @high1
  1875.  
  1876.    @raus:
  1877.      POP BP
  1878.    @LineReady:
  1879.   END;
  1880. END;
  1881.  
  1882. PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
  1883. { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
  1884. {     Color       = Farbe (0..255)             }
  1885. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke        }
  1886. {out: - }
  1887. {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
  1888. {     in der Farbe COLOR in den Hintergrundspeicher gezeichnet; die Rou-  }
  1889. {     tine fuehrt dabei selber alle notwendigen Umrechnungen und Clipping-}
  1890. {     schritte aus.                                                       }
  1891. {     Die Linie wird NICHT sofort sichtbar, sondern erst im naechsten Ani-}
  1892. {     mationszyklus (dann allerdings permanent)! (Deshalb ist es sinnvoll,}
  1893. {     diese Routine VOR dem Aufruf von ANIMATE auszufuehren, da dann alle }
  1894. {     Aenderungen (durch ANIMATE) sofort sichtbar werden)                 }
  1895. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwen-  }
  1896. {     dung der Routine nur fuer den Hintergrundmodus STATIC sinnvoll!     }
  1897. BEGIN
  1898.  Line(x1,y1,x2,y2,BACKGNDPAGE)
  1899. END;
  1900.  
  1901. FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
  1902. { in: x,y    = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  1903. {     PAGEADR= Grafikseite(nsegment), aus der gelesen werden soll  }
  1904. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke    }
  1905. {out: Farbe des Punktes}
  1906. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird  }
  1907. {     "0" als Ergebniswert zurueckgeliefert}
  1908. {     Achtung! Da PAGEADR immer die nichtsichtbare Grafikseite     }
  1909. {     bezeichnet, liest diese Routine auch von dort die Punkte ein!}
  1910. ASM
  1911.  XOR AL,AL              {AL mit 0 vorbesetzen}
  1912.  MOV DI,y
  1913.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  1914.  JS @offscrn
  1915.  CMP DI,YMAX
  1916.  JG @offscrn
  1917.  MOV BX,x
  1918.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  1919.  JS @offscrn
  1920.  CMP BX,XMAX
  1921.  JG @offscrn
  1922.  SHL DI,1
  1923.  MOV DI,CS:[OFFSET gadr + DI]
  1924.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  1925.  MOV AX,BX
  1926.  SHR AX,1
  1927.  SHR AX,1
  1928.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  1929.  AND BL,3     {BL = X MOD 4 = Leseplane}
  1930.  MOV AL,4
  1931.  MOV AH,BL
  1932.  MOV DX,3CEh
  1933.  
  1934.  MOV ES,PAGEADR
  1935.  CLI
  1936.  OUT DX,AX
  1937.  MOV AL,ES:[DI]
  1938.  STI
  1939. @offscrn:
  1940. END;
  1941.  
  1942. FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
  1943. { in: x,y   = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  1944. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke   }
  1945. {out: Farbe des Punktes der Hintergrundseite}
  1946. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
  1947. {     "0" als Ergebniswert zurueckgeliefert}
  1948. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die  }
  1949. {     Routine nur fuer den Hintergrundmodus STATIC sinnvoll!      }
  1950. ASM
  1951.  XOR AL,AL              {AL mit 0 vorbesetzen}
  1952.  MOV DI,y
  1953.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  1954.  JS @offscrn
  1955.  CMP DI,YMAX
  1956.  JG @offscrn
  1957.  MOV BX,x
  1958.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  1959.  JS @offscrn
  1960.  CMP BX,XMAX
  1961.  JG @offscrn
  1962.  SHL DI,1
  1963.  MOV DI,CS:[OFFSET gadr + DI]
  1964.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  1965.  MOV AX,BX
  1966.  SHR AX,1
  1967.  SHR AX,1
  1968.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  1969.  AND BL,3     {BL = X MOD 4 = Leseplane}
  1970.  MOV AL,4
  1971.  MOV AH,BL
  1972.  MOV DX,3CEh
  1973.  MOV ES,BACKGNDADR
  1974.  CLI
  1975.  OUT DX,AX
  1976.  MOV AL,ES:[DI]
  1977.  STI
  1978. @offscrn:
  1979. END;
  1980.  
  1981. FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE; ASSEMBLER;
  1982. { in: x,y   = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  1983. {     pa    = Grafikseite (0..3), von der der Punkt ausgelesen    }
  1984. {             werden soll}
  1985. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke   }
  1986. {out: Farbe des Punktes der Hintergrundseite}
  1987. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
  1988. {     "0" als Ergebniswert zurueckgeliefert}
  1989. {     Soll von der gerade SICHTBAREN Seite gelesen werden, so ist }
  1990. {     beim Aufruf als Seite "1-PAGE" anzugeben!                   }
  1991. {     Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK- }
  1992. {     GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
  1993. {     findet jedoch keine Ueberpruefung statt!}
  1994. ASM
  1995.  XOR AL,AL              {AL mit 0 vorbesetzen}
  1996.  MOV DI,y
  1997.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  1998.  JS @offscrn
  1999.  CMP DI,YMAX
  2000.  JG @offscrn
  2001.  MOV BX,x
  2002.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2003.  JS @offscrn
  2004.  CMP BX,XMAX
  2005.  JG @offscrn
  2006.  SHL DI,1
  2007.  MOV DI,CS:[OFFSET gadr + DI]
  2008.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2009.  MOV AX,BX
  2010.  SHR AX,1
  2011.  SHR AX,1
  2012.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2013.  AND BX,3     {BL = X MOD 4 = Leseplane; BH = 0}
  2014.  MOV AL,4
  2015.  MOV AH,BL
  2016.  MOV BL,pa    {BH=0 -> BX = Grafikseite}
  2017.  AND BX,3     {nur Seiten 0..3}
  2018.  SHL BX,1
  2019.  ADD BX,OFFSET Segment_Adr-StartIndex*2
  2020.  MOV ES,[BX]
  2021.  
  2022.  CLI
  2023.  MOV DX,3CEh
  2024.  OUT DX,AX
  2025.  MOV AL,ES:[DI]
  2026.  STI
  2027. @offscrn:
  2028. END;
  2029.  
  2030.  
  2031. PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
  2032. { in: x,y    = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2033. {     color  = Farbwert fuer den zu zeichnenden Punkt}
  2034. {     1-PAGE = Grafikseite, auf der gezeichnet werden soll}
  2035. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2036. {out: - }
  2037. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet  }
  2038. {     und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
  2039. {     Der Punkt wird NICHT automatisch in den Hintergrundspeicher ueber-   }
  2040. {     nommen, d.h.: er ist nur einen Animationszyklus lang sichtbar!       }
  2041. {     (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
  2042. {     zufuehren, da der gezeichnete Punkt sonst sofort wieder verschwindet)}
  2043. ASM
  2044.  MOV DI,y
  2045.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2046.  JS @offscrn
  2047.  CMP DI,YMAX
  2048.  JG @offscrn
  2049.  MOV BX,x
  2050.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2051.  JS @offscrn
  2052.  CMP BX,XMAX
  2053.  JG @offscrn
  2054.  SHL DI,1
  2055.  MOV DI,CS:[OFFSET gadr + DI]
  2056.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2057.  MOV AX,BX
  2058.  SHR AX,1
  2059.  SHR AX,1
  2060.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2061.  AND BX,3
  2062.  MOV AH,[OFFSET TranslateTab + BX]
  2063.  MOV AL,2
  2064.  MOV DX,3C4h
  2065.  
  2066.  MOV BX,1     {ES:=Segment_Adr[1-PAGE], denn 1-PAGE=sichtbare Seite}
  2067.  SUB BX,PAGE
  2068.  SHL BX,1
  2069.  ADD BX,OFFSET Segment_Adr-StartIndex*2
  2070.  MOV ES,[BX]
  2071.  
  2072.  CLI
  2073.  OUT DX,AX
  2074.  MOV AL,color
  2075.  STOSB
  2076.  STI
  2077. @offscrn:
  2078. END;
  2079.  
  2080. PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
  2081. { in: x,y   = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2082. {     color = Farbwert fuer den zu zeichnenden Punkt}
  2083. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2084. {out: - }
  2085. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet und}
  2086. {     in den Hintergrund gezeichnet (sofern er im sichtbaren Bereich liegt)  }
  2087. {     Der Punkt wird NICHT sofort sichtbar, sondern erst nach einem Anima-   }
  2088. {     tionszyklus (dann aber permanent) (Deshalb ist es sinnvoll, diese Rou- }
  2089. {     tine VOR dem Aufruf von ANIMATE auszufuehren, so dass evtl. Aenderungen}
  2090. {     des Hintergrundes "sofort" sichtbar werden!)                           }
  2091. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwendung  }
  2092. {     der Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
  2093. ASM
  2094.  MOV DI,y
  2095.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2096.  JS @offscrn
  2097.  CMP DI,YMAX
  2098.  JG @offscrn
  2099.  MOV BX,x
  2100.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2101.  JS @offscrn
  2102.  CMP BX,XMAX
  2103.  JG @offscrn
  2104.  SHL DI,1
  2105.  MOV DI,CS:[OFFSET gadr + DI]
  2106.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2107.  MOV AX,BX
  2108.  SHR AX,1
  2109.  SHR AX,1
  2110.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2111.  AND BX,3
  2112.  MOV AH,[OFFSET TranslateTab + BX]
  2113.  MOV AL,2
  2114.  MOV DX,3C4h
  2115.  MOV ES,BACKGNDADR
  2116.  CLI
  2117.  OUT DX,AX
  2118.  MOV AL,color
  2119.  STOSB
  2120.  STI
  2121. @offscrn:
  2122. END;
  2123.  
  2124. PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte); ASSEMBLER;
  2125. { in: x,y    = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2126. {     color  = Farbwert fuer den zu zeichnenden Punkt}
  2127. {     pa     = Grafikseite (0..3), auf der gezeichnet werden soll   }
  2128. {     PAGEADR= Grafikseite(nsegment), auf der gezeichnet werden soll}
  2129. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2130. {out: - }
  2131. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet  }
  2132. {     und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
  2133. {     Soll auf die gerade SICHTBARE Seite gezeichnet werden, so ist}
  2134. {     beim Aufruf als Seite "1-PAGE" anzugeben!                    }
  2135. {     Auch hier gilt, dass der gezeichnete Punkt NICHT automatisch }
  2136. {     in den Hintergrundspeicher uebernommen wird, d.h.: er ist nur}
  2137. {     bis zum naechsten Animationszyklus (= Aufruf von ANIMATE)    }
  2138. {     sichtbar! (Deshalb ist es sinnvoll, diese Routine NACH Aufruf}
  2139. {     von ANIMATE auszufuehren, da der gezeichnete Punkt sonst so- }
  2140. {     fort wieder verschwindet!)                                   }
  2141. {     Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK-  }
  2142. {     GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es  }
  2143. {     findet jedoch keine Ueberpruefung statt!}
  2144. ASM
  2145.  MOV DI,y
  2146.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2147.  JS @offscrn
  2148.  CMP DI,YMAX
  2149.  JG @offscrn
  2150.  MOV BX,x
  2151.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2152.  JS @offscrn
  2153.  CMP BX,XMAX
  2154.  JG @offscrn
  2155.  SHL DI,1
  2156.  MOV DI,CS:[OFFSET gadr + DI]
  2157.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2158.  MOV AX,BX
  2159.  SHR AX,1
  2160.  SHR AX,1
  2161.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2162.  AND BX,3
  2163.  MOV AH,[OFFSET TranslateTab + BX]
  2164.  MOV AL,2
  2165.  MOV DX,3C4h
  2166.  MOV BL,pa    {BH=0 -> BX=Grafikseite}
  2167.  SHL BX,1
  2168.  ADD BX,OFFSET Segment_Adr+StartIndex*2
  2169.  MOV ES,[BX]
  2170.  
  2171.  CLI
  2172.  OUT DX,AX
  2173.  MOV AL,color
  2174.  STOSB
  2175.  STI
  2176. @offscrn:
  2177. END;
  2178.  
  2179.  
  2180. PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
  2181. { in: (x,y)  = (virtuelle) Startkoordinaten des auszugebenden Textes}
  2182. {     s      = auszugebender Textstring                             }
  2183. {     pa     = Grafikseite, auf der der Text ausgegeben werden soll }
  2184. {     GraphTextColor=Textfarbe                                      }
  2185. {     GraphTextBackground=Farbe fuer Texthintergrund;ist dieser Wert}
  2186. {            =GraphTextColor, so werden nur die Textpixel gezeichnet}
  2187. {             und die umgebenden Pixel unveraendert gelassen (=nor- }
  2188. {             males Verhalten von TurboPascal's OutText-Routinen!)  }
  2189. {     GraphTextOrientation="vertical" oder "horizontal"             }
  2190. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke      }
  2191. {out: Text wurde auf dem Bildschirm ausgegeben                      }
  2192. VAR z,b,bit,i:BYTE;
  2193.     data:Fontchar;
  2194. BEGIN
  2195.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  2196.   THEN BEGIN
  2197.         Error:=Err_InvalidPageNumber;
  2198.         exit
  2199.        END;
  2200.  FOR i:=1 TO Length(s) DO
  2201.  BEGIN
  2202.   data:=FontData[ord(s[i])];
  2203.   FOR z:=0 TO FontHeight-1 DO
  2204.    BEGIN
  2205.     b:=data[z];
  2206.     FOR bit:=0 TO FontWidth-1 DO
  2207.      IF b and FontMask[bit]<>0
  2208.       THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
  2209.       ELSE IF (GraphTextColor<>GraphTextBackground)
  2210.             THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
  2211.    END;
  2212.   IF GraphTextOrientation=horizontal
  2213.    THEN INC(x,FontWidth)
  2214.    ELSE INC(y,FontHeight);
  2215.  END;
  2216. END;
  2217.  
  2218. PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
  2219. {rem: Wie OutTextXY(), aber es wird in den Hintergrund geschrieben und}
  2220. {     nicht in die durch PAGEADR spezifizierte Seite!                 }
  2221. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die      }
  2222. {     Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
  2223. VAR z,b,bit,i:BYTE;
  2224.     data:Fontchar;
  2225. BEGIN
  2226.  FOR i:=1 TO Length(s) DO
  2227.  BEGIN
  2228.   data:=FontData[ord(s[i])];
  2229.   FOR z:=0 TO FontHeight-1 DO
  2230.    BEGIN
  2231.     b:=data[z];
  2232.     FOR bit:=0 TO FontWidth-1 DO
  2233.      IF b and FontMask[bit]<>0
  2234.       THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
  2235.       ELSE IF (GraphTextColor<>GraphTextBackground)
  2236.             THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
  2237.    END;
  2238.   IF GraphTextOrientation=horizontal
  2239.    THEN INC(x,FontWidth)
  2240.    ELSE INC(y,FontHeight);
  2241.  END;
  2242. END;
  2243.  
  2244.  
  2245. FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
  2246. { in: s1,s2 = Spritepositionsnummern zweier Sprites}
  2247. {     SpriteN[s1],SpriteX[s1],SpriteY[s1] = Spritedaten von Sprite s1    }
  2248. {     SpriteN[s2],SpriteX[s2],SpriteY[s2] = Spritedaten von Sprite s2    }
  2249. {out: TRUE/FALSE fuer "Sprites kollidieren"/"Sprites kollidieren nicht"  }
  2250. {rem: Diese Ueberpruefung geschieht punktgenau und ist unabhaengig davon,}
  2251. {     ob die Sprites z.Z. gerade sichtbar sind oder nicht.               }
  2252. {     Inaktive Sprites (SpriteN[s?]=0) koennen nicht miteinander kollid. }
  2253. {     Ein Sprite kann nicht mit sich selbst kollidieren (s1=s2 -> FALSE) }
  2254. ASM
  2255.      MOV SI,s1               {1.Parameter s1 vom Stack holen}
  2256.      MOV DI,s2               {2.Parameter s2 vom Stack holen}
  2257.      CMP SI,DI
  2258.      JE  @NOHIT1             {Sprite kann sich nicht selbst treffen}
  2259.      SHL SI,1
  2260.      mov cx,[SI + OFFSET SpriteN]
  2261.      jcxz @NOHIT1            {Sprite <>0, d.h.: ueberhaupt aktiv?}
  2262.      SHL DI,1
  2263.      MOV BX,[DI + OFFSET SpriteN]
  2264.      OR  BX,BX               {dto. fuer anderes Sprite}
  2265.      JNE @PRUEF2
  2266.    @NOHIT1:
  2267.      JMP @NOHIT7             {inaktive Sprites koennen auch nicht}
  2268.                              {kollidieren -> FALSE zurueckgeben  }
  2269. {hier: SI (DI) = Zeiger auf 1. (2.) Sprite in ?WRTD[..] ,}
  2270. {      CX (BX) = Spritenummer von Sprite 1 (2)           }
  2271. {(etwas spaeter wird dann DS (ES) = Segment der Spr.daten von Spr.1 (2) )}
  2272.    @PRUEF2:
  2273.      MOV AX,[SI + OFFSET SpriteY]
  2274.      MOV DX,[DI + OFFSET SpriteY]
  2275.      mov si,[SI + OFFSET SpriteX]  {SI=x1}
  2276.      mov di,[DI + OFFSET SpriteX]  {DI=x2}
  2277.      shl bx,1                      {BX=Spritenummer2*2}
  2278.      mov es,[BX + OFFSET SPRITEAD] {ES=Segment der Spritedaten2}
  2279.      mov bx,cx                     {(CX=Spritenummer1)}
  2280.      shl bx,1                      {BX=Spritenummer1*2}
  2281.      MOV ds,[BX + OFFSET SPRITEAD]
  2282.  
  2283.      mov [y1],ax
  2284.      mov [y2],dx
  2285.      sub dx,ax
  2286.      mov CS:WORD PTR @y2_y1+1,dx
  2287.      mov [x1],si
  2288.      mov [x2],di
  2289.      mov dx,di
  2290.      sub dx,si
  2291.      mov CS:WORD PTR @x2_x1+1,dx
  2292.      mov ax,es:[Left]              {AX=Zeiger auf linke Randdaten}
  2293.      mov CS:WORD PTR @lirand2+1,ax
  2294.      mov ax,es:[Right]             {AX=Zeiger auf rechte Randdaten}
  2295.      mov CS:WORD PTR @rerand2+1,ax
  2296.      mov ax,es:[Top]               {AX=Zeiger auf obere Randdaten}
  2297.      mov CS:WORD PTR @orand2+1,ax
  2298.      mov ax,es:[Bottom]            {AX=Zeiger auf untere Randdaten}
  2299.      mov CS:WORD PTR @urand2+1,ax
  2300.      mov ax,es:[Breite]            {AX=max. Breite in 4er-Gruppen}
  2301.      shl al,1
  2302.      shl al,1
  2303.      mov CS:WORD PTR @breite2+1,ax {*4 = Breite in Punkten}
  2304.      mov ax,es:[Hoehe]
  2305.      mov CS:WORD PTR @hoehe2+1,ax  {Hoehe von Sprite2 in Punkten}
  2306.  
  2307.      MOV AX,[Left]                 {AX=Zeiger auf linke Randdaten}
  2308.      MOV CS:WORD PTR @LIRAND1+1,AX
  2309.      MOV AX,[Right]                {AX=Zeiger auf rechte Randdaten}
  2310.      MOV CS:WORD PTR @RERAND1+1,AX
  2311.      MOV AX,[Top]                  {AX=Zeiger auf obere Randdaten}
  2312.      MOV CS:WORD PTR @ORAND1+1,AX
  2313.      MOV AX,[Bottom]               {AX=Zeiger auf untere Randdaten}
  2314.      MOV CS:WORD PTR @URAND1+1,AX
  2315.      MOV BX,[Breite]               {BX=max. Breite in 4er-Gruppen}
  2316.      SHL BX,1
  2317.      SHL BX,1                      {*4 = Breite in Punkten}
  2318.      MOV CS:WORD PTR @BREITE1+2,BX
  2319.  
  2320.      lea bx,[si+bx-1]              {BX:=x1+breite1-1  (=x1last)}
  2321.    @breite2:
  2322.      mov bp,1234h                  {Dummywert}
  2323.      mov cx,bp                     {CX=breite2 brauchen wir spaeter nochmal}
  2324.      lea bp,[di+bp-1]              {BP:=x2+breite2-1  (=x2last)}
  2325.      cmp bx,bp
  2326.      jle @noex1
  2327.      mov bp,bx
  2328.    @noex1:                         {hier: BP=max(x1last,x2last)  (=maxx)}
  2329.      cmp si,di
  2330.      jle @X1_klgl_X2
  2331.      xchg si,di
  2332.    @X1_klgl_X2:                    {hier: SI=min(x1,x2)  (=minx)}
  2333.      stc
  2334.      sbb si,bp                     {SI:=minx-maxx-1=-(maxx-minx+1)}
  2335.    @breite1:
  2336.      add cx,1234h                  {(Dummywert)  CX:=breite1+breite2}
  2337.      add cx,si                     {CX:=breite1+breite2-(maxx-minx+1)}
  2338.      dec cx           {CX:=breite1+breite2-(maxx-minx+1)-1  (=ueberlappx-1)}
  2339.      js @NOHIT2                    {kein Treffer, wenn ueberlappx<=0}
  2340.      mov [ueberlappx_1],cx
  2341.  
  2342.      mov ax,[Hoehe]
  2343.      mov bx,ax                     {BX:=hoehe1}
  2344.      mov di,[y1]                   {DI:=y1}
  2345.      add ax,di                     {AX:=y1+hoehe1}
  2346.      dec ax                        {AX:=y1+hoehe1-1  (=y1last)}
  2347.    @hoehe2:
  2348.      mov si,1234h
  2349.      mov dx,[y2]
  2350.      add dx,si                     {DX:=y2+hoehe2}
  2351.      dec dx                        {DX:=y2+hoehe2-1  (=y2last)}
  2352.      cmp ax,dx
  2353.      jge @noex2
  2354.      mov ax,dx
  2355.    @noex2:                         {hier: AX=max(y1last,y2last)  (=maxy)}
  2356.      mov dx,[y2]
  2357.      cmp di,dx                     {(DI=y1)}
  2358.      jle @noex3
  2359.      mov di,dx
  2360.    @noex3:                         {hier: DI=min(y1,y2)  (=miny)}
  2361.      sub di,ax                     {DI:=miny-maxy=-(maxy-miny)}
  2362.      lea ax,[bx+si-2]              {AX:=hoehe1+hoehe2-2}
  2363.      add ax,di          {AX:=hoehe1+hoehe2-(maxy-miny+1)-1  (=ueberlappy-1)}
  2364.      js @NOHIT2                    {kein Treffer, wenn ueberlappy<=0}
  2365.      mov [ueberlappy_1],ax
  2366.  
  2367. {hier: AX=ueberlappy-1, CX=ueberlappx-1}
  2368.    @x2_x1:
  2369.      mov dx,1234h                  {Dummywert}
  2370.      xor bx,bx                     {ab jetzt: BX=0 !}
  2371.      or dx,dx
  2372.      js @X2_X1_kl_0                {if x2-x1>=0 then...}
  2373.      mov [hit2xfirst],bx           {...hit2xfirst:=0}
  2374.      mov [hit1xfirst],dx           {...hit1xfirst:=x2-x1}
  2375.      jmp @Yhits    {SHORT}
  2376.  
  2377. {Sprungleiste fuer NOHIT (passt hier gut hin)}
  2378.    @NOHIT2:
  2379.      JMP @NOHIT7
  2380.  
  2381. {jetzt wieder normales Programm}
  2382.    @X2_X1_kl_0:                    {else (x2-x1<0)...}
  2383.      mov [hit1xfirst],bx           {...hit1xfirst:=0}
  2384.      neg dx                        {DX:=x1-x2}
  2385.      mov [hit2xfirst],dx           {...hit2xfirst:=x1-x2}
  2386.  
  2387.    @Yhits:                         {hier: AX=ueberlappy-1}
  2388.    @y2_y1:
  2389.      mov dx,1234h                  {Dummywert}
  2390.      or dx,dx
  2391.      js @Y2_Y1_kl_0                {if y2-y1>=0 then...}
  2392.      mov [hit2yfirst],bx           {...hit2yfirst:=0}
  2393.      mov [hit1yfirst],dx           {...hit1yfirst:=y2-y1}
  2394.      jmp @iterate  {SHORT}
  2395.    @Y2_Y1_kl_0:                    {else (y2-y1<0)...}
  2396.      mov [hit1yfirst],bx           {...hit1yfirst:=0}
  2397.      neg dx                        {DX:=y1-y2}
  2398.      mov [hit2yfirst],dx           {...hit2yfirst:=y1-y2}
  2399.  
  2400. {Nun werden iterativ die ueberlappenden Zeilen und Spalten exakt geprueft}
  2401.    @iterate:
  2402.      mov cx,[ueberlappy_1]         {Anzahl der zu vergleichenden Zeilen -1}
  2403.      shl cx,1                      {*2, da Word-Werte!}
  2404.    @lirand1:
  2405.      mov si,1234h                  {Dummywert}
  2406.    @lirand2:
  2407.      mov di,1234h                  {Dummywert}
  2408.    @rerand1:
  2409.      mov bx,1234h                  {Dummywert}
  2410.    @rerand2:
  2411.      mov bp,1234h                  {Dummywert}
  2412.      sub bx,si                     {BX:=rerand1-lirand1}
  2413.      sub bp,di                     {BP:=rerand2-lirand2}
  2414.      mov ax,[hit1yfirst]
  2415.      shl ax,1
  2416.      add si,ax                  {SI:=1.Zeile, in der Sp.1 mit Sp.2 ueberlappt}
  2417.      mov ax,[hit2yfirst]
  2418.      shl ax,1
  2419.      add di,ax                  {DI:=1.Zeile, in der Sp.2 mit Sp.1 ueberlappt}
  2420.      add si,cx                  {dto., letzte Zeile}
  2421.      add di,cx
  2422.    @one_line:
  2423.      mov ax,[si]                   {DS:AX:=x1li[Zeile]}
  2424.      mov dx,es:[di]                {ES:DX:=x2li[Zeile]}
  2425.      add ax,[x1]                   {AX:=x1li[Zeile]+x1  (=c)}
  2426.      add dx,[x2]                   {DX:=x2li[Zeile]+x2  (=d)}
  2427.      cmp ax,dx
  2428.      jge @C_grgl_D
  2429.      mov ax,dx
  2430.    @C_grgl_D:                      {hier: AX=max(c,d)}
  2431.      mov cx,[si+bx]                {DS:CX:=x1re[Zeile]}
  2432.      mov dx,es:[di+bp]             {ES:DX:=x2re[Zeile]}
  2433.      add cx,[x1]                   {CX:=x1re[Zeile]+x1  (=a)}
  2434.      add dx,[x2]                   {DX:=x2re[Zeile]+x2  (=b)}
  2435.      cmp cx,dx
  2436.      jle @A_klgl_B
  2437.      mov cx,dx
  2438.    @A_klgl_B:                      {hier: CX=min(a,b)}
  2439.      cmp cx,ax                     {min(a,b)>=max(c,d) ?}
  2440.      jge @found_Xhit               {ja: Treffer in X-Richtung gefunden!}
  2441.      dec si                        {naechste Zeile (-> Word-Werte!)}
  2442.      dec si
  2443.      dec di
  2444.      dec di
  2445.      dec WORD PTR [ueberlappy_1]
  2446.      jns @one_line
  2447. {kein Treffer in X-Richtung -> ueberhaupt kein Treffer!}
  2448.      jmp @NOHIT7
  2449.  
  2450. {ansonsten: Treffer in X-Ri., jetzt noch Y-Ri. pruefen (analog zu oben) und }
  2451. {"Treffer!" nur dann ausgeben, falls auch mind. 1 Treffer in Y-Ri. existiert}
  2452.    @found_Xhit:
  2453.      mov cx,[ueberlappx_1]         {Anzahl der zu vergleichenden Spalten -1}
  2454.      shl cx,1                      {*2, da Word-Werte!}
  2455.    @orand1:
  2456.      mov si,1234h                  {Dummywert}
  2457.    @orand2:
  2458.      mov di,1234h                  {Dummywert}
  2459.    @urand1:
  2460.      mov bx,1234h                  {Dummywert}
  2461.    @urand2:
  2462.      mov bp,1234h                  {Dummywert}
  2463.      sub bx,si                     {BX:=urand1-orand1}
  2464.      sub bp,di                     {BP:=urand2-orand2}
  2465.      mov ax,[hit1xfirst]
  2466.      shl ax,1                      {*2, da Word-Werte!}
  2467.      add si,ax                     {SI:=orand1+2*hit1xfirst}
  2468.      mov ax,[hit2xfirst]
  2469.      shl ax,1                      {*2, da Word-Werte!}
  2470.      add di,ax                     {DI:=orand2+2*hit2xfirst}
  2471.      add si,cx
  2472.      add di,cx
  2473.    @one_column: mov ax,[si]        {AX:=y1ob[Spalte]}
  2474.      cmp ax,16000                  {Dummywert fuer "leere Spalte"?}
  2475.      je @next_column               {ja, also sicherlich kein Treffer}
  2476.      mov dx,es:[di]                {DX:=y2ob[Spalte]}
  2477.      cmp dx,16000                  {auch 2.Sprite pruefen: "leere Spalte"?}
  2478.      je @next_column               {ja, kein Treffer}
  2479.      add ax,[y1]                   {AX:=y1ob+y1  (=c)}
  2480.      add dx,[y2]                   {DX:=y2ob+y2  (=d)}
  2481.      cmp ax,dx
  2482.      jge @C_grgl_D2
  2483.      mov ax,dx
  2484.    @C_grgl_D2:                     {hier: AX=max(c,d)}
  2485.      mov cx,[si+bx]                {DS:CX:=y1un[Spalte]}
  2486.      mov dx,es:[di+bp]             {ES:DX:=y2un[Spalte]}
  2487.      add cx,[y1]                   {CX:=y1un+y1  (=a)}
  2488.      add dx,[y2]                   {DX:=y2un+y2  (=b)}
  2489.      cmp cx,dx
  2490.      jle @A_klgl_B2
  2491.      mov cx,dx
  2492.    @A_klgl_B2:                     {hier: CX=min(a,b)}
  2493.      cmp cx,ax                     {min(a,b)>=max(c,d) ?}
  2494.      jge @HIT2                     {ja: Treffer gefunden!}
  2495.    @next_column:
  2496.      dec si                        {nein, naechste Spalte (-> Word-Werte!)}
  2497.      dec si
  2498.      dec di
  2499.      dec di
  2500.      dec WORD PTR [ueberlappx_1]
  2501.      jns @one_column
  2502.  
  2503.    @NOHIT7:
  2504.      XOR AX,AX                     {als Ergebnis 0 = FALSE zurueckgeben}
  2505.      JMP @TREFF_END  {SHORT}
  2506.    @HIT2:
  2507.      MOV AX,1                      {als Ergebnis 1 = TRUE zurueckgeben}
  2508.  
  2509.    @TREFF_END:
  2510.      mov dx,seg @DATA              {BP wird von TP wiederhergestellt}
  2511.      mov ds,dx
  2512. END;
  2513.  
  2514.  
  2515. PROCEDURE Animate;
  2516. { in: PAGEADR = aktuelle Grafikseite(nadresse),auf der gezeichnet werden soll}
  2517. {     BACKGNDADR = Hintergrundseite(nadresse) }
  2518. {     BACKGROUNDMODE = STATIC/SCROLLING fuer festen/scrollbaren Hintergrund  }
  2519. {     SpriteN[] = Spritenummern der darzustellenden Sprites }
  2520. {     SpriteX[],SpriteY[] = deren zugehoergigen (virtuellen) Koordinaten}
  2521. {     StartVirtualX,StartVirtualY = obere linke Bildschirmecke  }
  2522. {     (PAGE = aktuell dargestellte Grafikseite) }
  2523. {out: PAGE = 0/1, wenn PAGE vorher 1/0 war }
  2524. {     PAGEADR = neue, aktuelle Grafikseite(nadresse) }
  2525. {rem: Animate loescht den Inhalt der alten Grafik (mithilfe der Hintergrund- }
  2526. {     seite), zeichnet alle sichtbaren Sprites, synchronisiert auf das vert. }
  2527. {     Retracesignal und schaltet dann auf die so fertiggestellte Seite um.   }
  2528. VAR offsetXTiles,offsetYTiles,offsetXPix,offsetYPix:INTEGER;
  2529.     leftcut,rightcut,topcut,bottomcut,tiles:WORD;
  2530.     x,y,xpix,ypix,xtil,ytil,actindex,randindex,index:INTEGER;
  2531.     offscreenFlag:BYTE;
  2532.     yt,xt:INTEGER;
  2533. BEGIN
  2534.  ASM
  2535.     CLD
  2536.     {zuerst das Hintergrundbild auf die aktuelle Seite kopieren:}
  2537.     CMP BackgroundMode,STATIC   {welcher Hintergrundmodus?}
  2538.     JE @static_bckgnd
  2539.     JMP @scrolling_bckgnd
  2540.  
  2541.   @static_bckgnd:
  2542.     MOV AX,0F02h                {alle 4 Planes gleichzeitig beschreiben}
  2543.     MOV DX,3C4h
  2544.     OUT DX,AX
  2545.     MOV AX,4105h                {Schreibmodus 1 waehlen}
  2546.     MOV DX,3CEh
  2547.     OUT DX,AX
  2548.  
  2549.     MOV ES,PAGEADR              {Grafikseite mit Hintergrundmuster fuellen}
  2550.     MOV DS,BACKGNDADR
  2551.     XOR SI,SI
  2552.     MOV DI,SI
  2553.     MOV CX,PAGESIZE
  2554.  
  2555.     REP MOVSB
  2556.  
  2557.     MOV AX,SEG @DATA
  2558.     MOV DS,AX
  2559.     MOV AX,4005h     {Writemode 0 setzen}
  2560.     MOV DX,3CEh
  2561.     OUT DX,AX
  2562.  
  2563.     JMP @Sprites_zeichnen
  2564.  
  2565.   {---------------------------------}
  2566.  
  2567.   @scrolling_bckgnd:      {ab hier: Hintergrund aus Kacheln zusammensetzen}
  2568.     MOV AX,StartVirtualY
  2569.     MOV BX,AX             {AX=BX=StartVirtualY}
  2570.     SUB AX,BackY1
  2571.     ADD AX,15             {offsetYTiles:=(StartVirtualY-BackY1+15)DIV16}
  2572.     SAR AX,1
  2573.     SAR AX,1
  2574.     SAR AX,1
  2575.     SAR AX,1
  2576.     MOV offsetYTiles,AX
  2577.     MOV ytil,AX           {ytil:=offsetYTiles}
  2578.     DEC AX
  2579.     IMUL XTiles
  2580.     DEC AX
  2581.     MOV actIndex,AX       {actIndex:=(ytil-1)*XTiles-1, "+xtil" kommt spaeter}
  2582.  
  2583.     MOV AX,16
  2584.     SUB AX,BX             {BX=StartVirtualY}
  2585.     AND AX,$F
  2586.     MOV ypix,AX           {ypix:=(16-StartVirtualY) AND $F}
  2587.     SUB AX,200
  2588.     AND AX,$F
  2589.     MOV bottomcut,AX      {bottomcut:=(ypix-200) AND $F}
  2590.  
  2591.     AND BX,$F             {offsetYPix:=topcut:=StartVirtualY AND $F}
  2592.     MOV topcut,BX
  2593.     MOV offsetYPix,BX
  2594.  
  2595.     MOV AX,StartVirtualX
  2596.     MOV BX,AX             {AX=BX=StartVirtualX}
  2597.     SUB AX,BackX1
  2598.     ADD AX,15             {offsetXTiles:=(StartVirtualX-BackX1+15)DIV16}
  2599.     SAR AX,1
  2600.     SAR AX,1
  2601.     SAR AX,1
  2602.     SAR AX,1
  2603.     MOV offsetXTiles,AX
  2604.     MOV xtil,AX           {xtil:=offsetXTiles}
  2605.     ADD actIndex,AX       {actIndex:=(ytil-1)*XTiles-1+xtil}
  2606.  
  2607.     MOV AX,16
  2608.     SUB AX,BX             {BX=StartVirtualX}
  2609.     AND AX,$F
  2610.     MOV xpix,AX           {xpix=rightcut:=(16-StartVirtualX) AND $F}
  2611.     MOV rightcut,AX
  2612.  
  2613.     AND BX,$F             {offsetXPix:=leftcut:=StartVirtualX AND $F}
  2614.     MOV leftcut,BX
  2615.     MOV offsetXPix,BX
  2616.  
  2617.     MOV AX,(XMAX+1)/16-1
  2618.     SUB BL,1              {C=1, wenn leftcut=0}
  2619.     ADC AX,0
  2620.     MOV tiles,AX          {tiles:=19+ord(leftcut=0)}
  2621.  
  2622.  
  2623.     CMP topcut,0          {wenn topcut=0 ist, braucht die oberste}
  2624.     JE @do_innertiles     {Tilezeile nicht gesondert gezeichnet werden}
  2625.  
  2626.     {oberste Tilezeile:}
  2627.     MOV DX,xtil
  2628.     MOV xt,DX
  2629.     MOV AX,ytil
  2630.     DEC AX
  2631.     MOV yt,AX
  2632.     MOV CL,1
  2633.     JS @offscreen
  2634.     CMP AX,YTiles
  2635.     JAE @offscreen
  2636.     DEC CL
  2637.   @offscreen:  {CL=0/1 fuer offscreenFlag=false/true=(yt<0) OR (yt>=YTiles}
  2638.     MOV offscreenFlag,CL
  2639.  
  2640.     CMP leftcut,0          {wenn leftcut=0 ist, muss die linke obere}
  2641.     JE @do_upperinnertiles {Ecke nicht gesondert gezeichnet werden  }
  2642.  
  2643.     {linke obere Eck-Tile zeichnen:}    {CL=offscreenFlag, DX=xt}
  2644.     XOR SI,SI   {Tileindex bestimmen:}
  2645.     DEC CL      {IF offscreenFlag OR (xt-1<0) OR (xt-1>=XTiles) }
  2646.     JZ @go1     { THEN index:=0 ELSE index:=actIndex}
  2647.     DEC DX
  2648.     JS @go1
  2649.     CMP DX,XTiles
  2650.     JAE @go1
  2651.     MOV SI,actIndex  {=yt*XTiles+(xt-1)}
  2652.   @go1:
  2653.  
  2654.        {PROCEDURE DrawUpperLeftTile(leftcut,topcut:INTEGER; index:WORD);}
  2655.        { in: leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  2656.        {     topcut  = dto., oben}
  2657.        {     SI = index = Tilenummer}
  2658.        {out: Tile wurde auf aktueller Seite PAGEADR bei (0,0) gezeichnet}
  2659.        {rem: Tile wurde links und oben entsprechend geschnitten}
  2660.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  2661.        {     topcut  muss zwischen 0 und 15 liegen, 16 ist verboten}
  2662.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  2663.        XOR AL,AL
  2664.  
  2665.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  2666.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  2667.        SHR AH,1    {rechtsschieben!}
  2668.        RCR AL,1
  2669.        MOV SI,topcut
  2670.        MOV CX,16
  2671.        SUB CX,SI   {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
  2672.        SHL SI,1
  2673.        SHL SI,1    {fuer jede oben abgeschnittene Zeile 4 Bytes}
  2674.        ADD SI,AX   {zur (Offset-)Quelladresse in Page 3 addieren}
  2675.  
  2676.        XOR DI,DI   {die erste Zieladresse ist DI:=0*LINESIZE+(0 div 4)=0}
  2677.  
  2678.        MOV AX,leftcut
  2679.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  2680.        SHR AX,1
  2681.        SHR AX,1
  2682.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  2683.  
  2684.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  2685.        {verwendet werden!}
  2686.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  2687.        MOV BP,16+3
  2688.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  2689.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  2690.  
  2691.  
  2692.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  2693.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  2694.  
  2695.        MOV DX,3CEh
  2696.        AND BL,3
  2697.        MOV AH,BL   {AH:=leftcut mod 4}
  2698.        MOV AL,4
  2699.  
  2700.        JNE @mode0a {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  2701.  
  2702.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  2703.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  2704.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  2705.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  2706.        MOV AX,4105h
  2707.        OUT DX,AX   {WriteMode 1 waehlen}
  2708.        MOV DX,3C4h
  2709.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  2710.        OUT DX,AX
  2711.        JMP @lastPlane1  {abkuerzen}
  2712.        {---}
  2713.  
  2714.      @mode0a:
  2715.        OUT DX,AX   {aktuelle Leseplane waehlen}
  2716.        PUSH AX     {und fuer spaeter merken}
  2717.  
  2718.        MOV DX,3C4h
  2719.        MOV AX,0102h    {Schreibplane 0 waehlen}
  2720.        OUT DX,AX
  2721.  
  2722.        MOV BX,BP
  2723.        SHR BX,1
  2724.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  2725.  
  2726.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  2727.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  2728.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  2729.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  2730.  
  2731.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  2732.        PUSH DI
  2733.        PUSH BP     {BP retten}
  2734.        PUSH CX     {CX = Zeilenzaehler retten}
  2735.        MOV BP,CX   {BP:=Zeilenzaehler}
  2736.      @eineZeile1a:
  2737.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  2738.        REP MOVSB   {eine Zeile uebertragen}
  2739.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  2740.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  2741.        DEC BP
  2742.        JNZ @eineZeile1a
  2743.        POP CX
  2744.        POP BP
  2745.        POP DI
  2746.        POP SI
  2747.  
  2748.        MOV DX,3C4h
  2749.        MOV AX,0202h  {Schreibplane 1 waehlen}
  2750.        OUT DX,AX
  2751.  
  2752.        MOV DX,3CEh   {naechste Leseplane:}
  2753.        POP AX
  2754.        INC AH
  2755.        AND AH,3      {um 1 erhoehen MOD 4}
  2756.        JNE @nowrap1a
  2757.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  2758.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  2759.      @nowrap1a:
  2760.        OUT DX,AX
  2761.        PUSH AX
  2762.  
  2763.  
  2764.        DEC BP        {BP:=16+2-leftcut}
  2765.        MOV BX,BP
  2766.        SHR BX,1
  2767.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  2768.  
  2769.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  2770.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  2771.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  2772.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  2773.  
  2774.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  2775.        PUSH DI
  2776.        PUSH BP     {BP retten}
  2777.        PUSH CX     {Zeilenzaehler retten}
  2778.        MOV BP,CX   {BP:=Zeilenzaehler}
  2779.      @eineZeile2a:
  2780.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  2781.        REP MOVSB   {eine Zeile uebertragen}
  2782.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  2783.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  2784.        DEC BP
  2785.        JNZ @eineZeile2a
  2786.        POP CX
  2787.        POP BP
  2788.        POP DI
  2789.        POP SI
  2790.  
  2791.        MOV DX,3C4h
  2792.        MOV AX,0402h  {Schreibplane 2 waehlen}
  2793.        OUT DX,AX
  2794.  
  2795.        MOV DX,3CEh   {naechste Leseplane:}
  2796.        POP AX
  2797.        INC AH
  2798.        AND AH,3      {um 1 erhoehen MOD 4}
  2799.        JNE @nowrap2a
  2800.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  2801.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  2802.      @nowrap2a:
  2803.        OUT DX,AX
  2804.        PUSH AX
  2805.  
  2806.  
  2807.        DEC BP        {BP:=16+1-leftcut}
  2808.        MOV BX,BP
  2809.        SHR BX,1
  2810.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  2811.  
  2812.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  2813.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  2814.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  2815.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  2816.  
  2817.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  2818.        PUSH DI
  2819.        PUSH BP     {BP retten}
  2820.        PUSH CX     {Zeilenzaehler retten}
  2821.        MOV BP,CX   {BP:=Zeilenzaehler}
  2822.      @eineZeile3a:
  2823.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  2824.        REP MOVSB   {eine Zeile uebertragen}
  2825.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  2826.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  2827.        DEC BP
  2828.        JNZ @eineZeile3a
  2829.        POP CX
  2830.        POP BP
  2831.        POP DI
  2832.        POP SI
  2833.  
  2834.        MOV DX,3C4h
  2835.        MOV AX,0802h  {Schreibplane 3 waehlen}
  2836.        OUT DX,AX
  2837.  
  2838.        MOV DX,3CEh   {naechste Leseplane:}
  2839.        POP AX
  2840.        INC AH
  2841.        AND AH,3      {um 1 erhoehen MOD 4}
  2842.        JNE @nowrap3a
  2843.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  2844.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  2845.      @nowrap3a:
  2846.        OUT DX,AX
  2847.  
  2848.  
  2849.        DEC BP        {BP:=16-leftcut}
  2850.      @lastplane1:
  2851.                      {BP direkt verwenden}
  2852.        SHR BP,1
  2853.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  2854.  
  2855.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  2856.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  2857.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  2858.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  2859.  
  2860.                        {Quell- und Zieladresse nicht mehr retten}
  2861.        MOV BX,CX   {BX:=Zeilenzaehler}
  2862.      @eineZeile4a:
  2863.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  2864.        REP MOVSB   {eine Zeile uebertragen}
  2865.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  2866.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  2867.        DEC BX
  2868.        JNZ @eineZeile4a
  2869.  
  2870.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  2871.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  2872.        MOV AX,4005h
  2873.        MOV DX,3CEh
  2874.        OUT DX,AX
  2875.        {---}
  2876.  
  2877.        POP BP
  2878.        MOV AX,SEG @Data  {DS wiederherstellen}
  2879.        MOV DS,AX
  2880.  
  2881.   {Nun alle anderen oberen Kacheln, die nur oben (aber nicht seitlich)}
  2882.   {abgeschnitten sind: }
  2883.   @do_upperinnertiles:
  2884.     MOV AX,xpix
  2885.     MOV x,AX
  2886.     INC actIndex
  2887.  
  2888.   @repeat1:  {Schleife wird genau "tiles" mal durchlaufen}
  2889.     MOV CL,offscreenFlag
  2890.     XOR SI,SI  {Tileindex bestimmen:}
  2891.     DEC CL     {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
  2892.     JZ @go2    { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
  2893.     MOV DX,xt
  2894.     OR DX,DX
  2895.     JS @go2
  2896.     CMP DX,XTiles
  2897.     JAE @go2
  2898.     MOV SI,actIndex
  2899.   @go2:
  2900.  
  2901.  
  2902.        {PROCEDURE DrawUpperTile(x,topcut:INTEGER; index:WORD);}
  2903.        { in: (x,0) = linke obere Ecke der zu zeichnenden Tile,}
  2904.        {     topcut= Anzahl abzuschneidende Zeilen}
  2905.        {     SI = index = Tilenummer}
  2906.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  2907.        {rem: Tile muss links, rechts (und unten) ganz auf dem Bildschirm sein}
  2908.        {     topcut muss im Stapel liegen (da DS andersweitig belegt wird!}
  2909.        {     topcut muss Werte zwischen 0..15 haben, 16 ist unzulaessig!}
  2910.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  2911.        XOR AL,AL
  2912.  
  2913.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  2914.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  2915.        SHR AH,1    {rechtsschieben!}
  2916.        RCR AL,1    {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  2917.  
  2918.        MOV SI,topcut  {Dazu kommen die oben abgeschnittenen Zeilen:}
  2919.        MOV CX,16      {fuer jede Zeile 4 Bytes}
  2920.        SUB CX,SI      {CX:=16-topcut = zu zeichnende Zeilen}
  2921.        SHL SI,1
  2922.        SHL SI,1
  2923.        ADD SI,AX   {SI = Zeiger auf erstes zu kopierendes Tilebyte}
  2924.  
  2925.        {Die erste Zieladresse ist DI:=0*LINESIZE+(x div 4) = x div 4}
  2926.        MOV DI,x
  2927.        MOV BX,DI   {Kopie von X in BX aufbewahren}
  2928.        SHR DI,1
  2929.        SHR DI,1
  2930.  
  2931.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  2932.        {verwendet werden!}
  2933.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  2934.        MOV BP,CX
  2935.        SHL BP,1
  2936.        SHL BP,1    {BP := (zu zeichnende Zeilen)*4 }
  2937.  
  2938.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  2939.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  2940.  
  2941.        MOV DX,3C4h
  2942.        MOV AL,2
  2943.        AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  2944.        JNE @mode0b {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  2945.  
  2946.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  2947.        MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  2948.        OUT DX,AX
  2949.        MOV AX,4105h
  2950.        MOV DX,3CEh
  2951.        OUT DX,AX   {WriteMode 1 waehlen}
  2952.        MOV BX,CX   {BX:=CX=zu zeichnende Zeilen}
  2953.        JMP @lastPlane2  {abkuerzen}
  2954.        {---}
  2955.  
  2956.      @mode0b:
  2957.        MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  2958.        OUT DX,AX
  2959.        PUSH AX     {aktuelle Schreibplane merken}
  2960.  
  2961.        MOV DX,3CEh
  2962.        MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  2963.        OUT DX,AX
  2964.  
  2965.        MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  2966.        MOV BX,CX   {zu zeichnende Zeilenzahl nach BX retten}
  2967.      @eineZeile1b:
  2968.        MOVSB
  2969.        MOVSB
  2970.        MOVSB
  2971.        MOVSB
  2972.        ADD DI,AX   {DI auf naechste Zeile setzen}
  2973.        LOOP @eineZeile1b
  2974.  
  2975.        MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  2976.        OUT DX,AX
  2977.  
  2978.        MOV DX,3C4h   {naechste Schreibplane:}
  2979.        POP AX
  2980.        SHL AH,1
  2981.        CMP AH,16
  2982.        JNE @nowrap1b
  2983.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  2984.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  2985.      @nowrap1b:
  2986.        OUT DX,AX
  2987.        PUSH AX
  2988.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  2989.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  2990.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  2991.        SUB SI,BP     {SI auch zuruecksetzen}
  2992.  
  2993.  
  2994.        MOV AX,LINESIZE-4
  2995.        MOV CX,BX   {CX:=zu zeichnende Zeilenanzahl}
  2996.      @eineZeile2b:
  2997.        MOVSB
  2998.        MOVSB
  2999.        MOVSB
  3000.        MOVSB
  3001.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3002.        LOOP @eineZeile2b
  3003.  
  3004.        POP AX
  3005.        SHL AH,1
  3006.        CMP AH,16
  3007.        JNE @nowrap2b
  3008.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3009.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3010.      @nowrap2b:
  3011.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3012.        PUSH AX
  3013.        MOV DX,3CEh
  3014.        MOV AX,0204h  {Leseplane 2 setzen}
  3015.        OUT DX,AX
  3016.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  3017.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  3018.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  3019.        SUB SI,BP     {SI auch zuruecksetzen}
  3020.  
  3021.  
  3022.        MOV AX,LINESIZE-4
  3023.        MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  3024.      @eineZeile3b:
  3025.        MOVSB
  3026.        MOVSB
  3027.        MOVSB
  3028.        MOVSB
  3029.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3030.        LOOP @eineZeile3b
  3031.  
  3032.        MOV AX,0304h
  3033.        OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  3034.        MOV DX,3C4h
  3035.        POP AX
  3036.        SHL AH,1
  3037.        CMP AH,16
  3038.        JNE @nowrap3b
  3039.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3040.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3041.      @nowrap3b:
  3042.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3043.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  3044.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  3045.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  3046.        SUB SI,BP     {SI auch zuruecksetzen}
  3047.  
  3048.  
  3049.      @lastPlane2:
  3050.        MOV AX,LINESIZE-4
  3051.        MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  3052.      @eineZeile4b:
  3053.        MOVSB
  3054.        MOVSB
  3055.        MOVSB
  3056.        MOVSB
  3057.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3058.        LOOP @eineZeile4b
  3059.  
  3060.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  3061.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  3062.        MOV AX,4005h
  3063.        MOV DX,3CEh
  3064.        OUT DX,AX
  3065.        {---}
  3066.  
  3067.        POP BP
  3068.        MOV AX,SEG @Data  {DS wiederherstellen}
  3069.        MOV DS,AX
  3070.  
  3071.     INC xt        {Tilezaehler in X-Richtung erhoehen}
  3072.     INC actIndex  {wg. actIndex=yt*XTiles+xt auch actIndex erhoehen}
  3073.     MOV AX,x      {aktuelle X-Koord. auch weitersetzen: x:=x+16}
  3074.     ADD AX,16
  3075.     MOV x,AX
  3076.     CMP AX,XMAX+1-16
  3077.     JBE @repeat1  {bis rechte obere Ecke erreicht}
  3078.  
  3079.     {Jetzt obere rechte Eck-Kachel - falls nicht schon gezeichnet:}
  3080.     CMP AX,XMAX+1
  3081.     JE @label1
  3082.  
  3083.     MOV CL,offscreenFlag  {ja, Ecke muss noch gezeichnet werden}
  3084.     XOR SI,SI  {Tileindex bestimmen:}
  3085.     DEC CL     {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
  3086.     JZ @go3    { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
  3087.     MOV DX,xt
  3088.     OR DX,DX
  3089.     JS @go3
  3090.     CMP DX,XTiles
  3091.     JAE @go3
  3092.     MOV SI,actIndex
  3093.   @go3:
  3094.  
  3095.  
  3096.        {PROCEDURE DrawUpperRightTile(x,rightcut,topcut:INTEGER; index:WORD);}
  3097.        { in: (x,0) = linke obere Ecke der zu zeichnenden Tile}
  3098.        {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  3099.        {     topcut   = dto., oben}
  3100.        {     SI = index = Tilenummer}
  3101.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3102.        {rem: Tile wurde rechts und oben entsprechend geschnitten}
  3103.        {     topcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  3104.        {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  3105.        {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  3106.        {     rightcut := x+15-xmax }
  3107.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3108.        XOR AL,AL
  3109.  
  3110.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3111.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3112.        SHR AH,1    {rechtsschieben!}
  3113.        RCR AL,1
  3114.        MOV SI,topcut
  3115.        MOV CX,16
  3116.        SUB CX,SI   {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
  3117.        SHL SI,1
  3118.        SHL SI,1    {fuer jede oben abgeschnittene Zeile 4 Bytes}
  3119.        ADD SI,AX   {zur (Offset-)Quelladresse in Page 3 addieren}
  3120.  
  3121.        MOV DI,x    {erste Zieladresse ist DI:=0*LINESIZE +(x div 4)=x div 4}
  3122.        MOV BX,DI   {Kopie von x nach BX}
  3123.        SHR DI,1
  3124.        SHR DI,1
  3125.  
  3126.        MOV AX,rightcut
  3127.  
  3128.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  3129.        {verwendet werden!}
  3130.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  3131.        MOV BP,16+3
  3132.        SUB BP,AX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  3133.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  3134.        MOV AH,AL   {rightcut nach AH retten}
  3135.  
  3136.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3137.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3138.  
  3139.        MOV DX,3C4h
  3140.        MOV AL,2
  3141.        AND BX,3
  3142.  
  3143.        JNE @mode0c {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  3144.        AND AH,3    {wir WriteMode1 verwenden!}
  3145.        JNE @mode0c
  3146.  
  3147.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  3148.        MOV AH,0Fh
  3149.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  3150.        MOV DX,3CEh
  3151.        MOV AX,4105h {WriteMode 1 waehlen}
  3152.        OUT DX,AX
  3153.        SUB BP,3     {BP auf die richtige Groesse bringen}
  3154.        JMP @lastPlane3  {abkuerzen}
  3155.        {---}
  3156.  
  3157.      @mode0c:
  3158.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  3159.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  3160.        PUSH AX     {und fuer spaeter merken}
  3161.  
  3162.        MOV DX,3CEh
  3163.        MOV AX,0004h    {Leseplane 0 waehlen}
  3164.        OUT DX,AX
  3165.  
  3166.        MOV BX,BP
  3167.        SHR BX,1
  3168.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  3169.  
  3170.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3171.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  3172.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3173.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  3174.  
  3175.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3176.        PUSH DI
  3177.        PUSH BP     {BP retten}
  3178.        PUSH CX     {CX = Zeilenzaehler retten}
  3179.        MOV BP,CX   {BP:=Zeilenzaehler}
  3180.      @eineZeile1c:
  3181.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3182.        REP MOVSB   {eine Zeile uebertragen}
  3183.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3184.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3185.        DEC BP
  3186.        JNZ @eineZeile1c
  3187.        POP CX
  3188.        POP BP
  3189.        POP DI
  3190.        POP SI
  3191.  
  3192.        MOV DX,3CEh
  3193.        MOV AX,0104h  {Leseplane 1 waehlen}
  3194.        OUT DX,AX
  3195.  
  3196.        MOV DX,3C4h   {naechste Schreibplane:}
  3197.        POP AX
  3198.        SHL AH,1
  3199.        CMP AH,16
  3200.        JNE @nowrap1c
  3201.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3202.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3203.      @nowrap1c:
  3204.        OUT DX,AX
  3205.        PUSH AX
  3206.  
  3207.  
  3208.        DEC BP        {BP:=16+2-rightcut}
  3209.        MOV BX,BP
  3210.        SHR BX,1
  3211.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  3212.  
  3213.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3214.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  3215.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3216.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  3217.  
  3218.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3219.        PUSH DI
  3220.        PUSH BP     {BP retten}
  3221.        PUSH CX     {CX = Zeilenzaehler retten}
  3222.        MOV BP,CX   {BP:=Zeilenzaehler}
  3223.      @eineZeile2c:
  3224.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3225.        REP MOVSB   {eine Zeile uebertragen}
  3226.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3227.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3228.        DEC BP
  3229.        JNZ @eineZeile2c
  3230.        POP CX
  3231.        POP BP
  3232.        POP DI
  3233.        POP SI
  3234.  
  3235.        MOV DX,3CEh
  3236.        MOV AX,0204h  {Leseplane 2 waehlen}
  3237.        OUT DX,AX
  3238.  
  3239.        MOV DX,3C4h   {naechste Schreibplane:}
  3240.        POP AX
  3241.        SHL AH,1
  3242.        CMP AH,16
  3243.        JNE @nowrap2c
  3244.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3245.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3246.      @nowrap2c:
  3247.        OUT DX,AX
  3248.        PUSH AX
  3249.  
  3250.  
  3251.        DEC BP        {BP:=16+1-rightcut}
  3252.        MOV BX,BP
  3253.        SHR BX,1
  3254.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  3255.  
  3256.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3257.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  3258.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3259.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  3260.  
  3261.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3262.        PUSH DI
  3263.        PUSH BP     {BP retten}
  3264.        PUSH CX     {CX = Zeilenzaehler retten}
  3265.        MOV BP,CX   {BP:=Zeilenzaehler}
  3266.      @eineZeile3c:
  3267.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3268.        REP MOVSB   {eine Zeile uebertragen}
  3269.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3270.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3271.        DEC BP
  3272.        JNZ @eineZeile3c
  3273.        POP CX
  3274.        POP BP
  3275.        POP DI
  3276.        POP SI
  3277.  
  3278.        MOV DX,3CEh
  3279.        MOV AX,0304h  {Leseplane 3 waehlen}
  3280.        OUT DX,AX
  3281.  
  3282.        MOV DX,3C4h   {naechste Schreibplane:}
  3283.        POP AX
  3284.        SHL AH,1
  3285.        CMP AH,16
  3286.        JNE @nowrap3c
  3287.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3288.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3289.      @nowrap3c:
  3290.        OUT DX,AX
  3291.                      {Wert nicht mehr pushen!}
  3292.  
  3293.  
  3294.        DEC BP        {BP:=16-rightcut}
  3295.      @lastplane3:
  3296.                      {BP direkt verwenden}
  3297.        SHR BP,1
  3298.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  3299.  
  3300.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3301.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3302.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3303.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3304.  
  3305.                        {Quell- und Zieladresse nicht mehr retten}
  3306.        MOV BX,CX   {BX:=Zeilenzaehler}
  3307.      @eineZeile4c:
  3308.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  3309.        REP MOVSB   {eine Zeile uebertragen}
  3310.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3311.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3312.        DEC BX
  3313.        JNZ @eineZeile4c
  3314.  
  3315.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  3316.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  3317.        MOV AX,4005h
  3318.        MOV DX,3CEh
  3319.        OUT DX,AX
  3320.        {---}
  3321.  
  3322.        POP BP
  3323.        MOV AX,SEG @Data  {DS wiederherstellen}
  3324.        MOV DS,AX
  3325.  
  3326.   @label1:
  3327.     MOV AX,actIndex  {actIndex fuer naechste Tilezeile justieren:}
  3328.     STC              {actIndex:=actIndex-tiles+1}
  3329.     SBB AX,tiles
  3330.     MOV actIndex,AX
  3331.  
  3332.   {Jetzt alle vollstaendig im Inneren des Bildschirms gelegenen }
  3333.   {(d.h.: nicht abgeschnittene) Tiles zeichnen:}
  3334.   @do_innertiles:
  3335.     MOV AX,ypix
  3336.     MOV y,AX
  3337.     MOV AX,actIndex
  3338.     ADD AX,XTiles
  3339.     MOV RandIndex,AX
  3340.     INC AX
  3341.     MOV actIndex,AX
  3342.  
  3343.   @repeat2:
  3344.     MOV AX,ytil
  3345.     MOV CL,1
  3346.     OR AX,AX
  3347.     JS @go4
  3348.     CMP AX,YTiles
  3349.     JAE @go4
  3350.     DEC CL
  3351.   @go4:
  3352.     MOV offscreenFlag,CL
  3353.     MOV AX,xpix
  3354.     MOV x,AX
  3355.     MOV AX,offsetXTiles
  3356.     MOV xtil,AX
  3357.  
  3358.   @repeat3:
  3359.     MOV CL,offscreenFlag
  3360.     XOR SI,SI
  3361.     DEC CL
  3362.     JZ @go5
  3363.     OR AX,AX
  3364.     JS @go5
  3365.     CMP AX,XTiles
  3366.     JAE @go5
  3367.     MOV SI,actIndex
  3368.   @go5:
  3369.  
  3370.  
  3371.        {PROCEDURE DrawInnerTile(x,y:INTEGER; index:WORD);}
  3372.        { in: (x,y) = linke obere Ecke der zu zeichnenden Tile,}
  3373.        {     SI = index = Tilenummer}
  3374.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3375.        {rem: Tile muss ganz auf dem Bildschirm sein, es findet}
  3376.        {     kein Clipping statt}
  3377.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3378.        XOR AL,AL
  3379.  
  3380.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3381.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3382.        SHR AH,1    {rechtsschieben!}
  3383.        RCR AL,1
  3384.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  3385.  
  3386.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  3387.        SHL DI,1
  3388.        MOV DI,CS:[OFFSET GADR + DI]
  3389.        MOV AX,x
  3390.        MOV BX,AX   {Kopie von X in BX aufbewahren}
  3391.        SHR AX,1
  3392.        SHR AX,1
  3393.        ADD DI,AX
  3394.  
  3395.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3396.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3397.  
  3398.        MOV DX,3C4h
  3399.        MOV AL,2
  3400.        AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  3401.        JNE @mode0d {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  3402.  
  3403.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  3404.        MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  3405.        OUT DX,AX
  3406.        MOV AX,4105h
  3407.        MOV DX,3CEh
  3408.        OUT DX,AX   {WriteMode 1 waehlen}
  3409.        MOV BX,4
  3410.        JMP @lastPlane4  {abkuerzen}
  3411.        {---}
  3412.  
  3413.      @mode0d:
  3414.        MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  3415.        OUT DX,AX
  3416.        PUSH AX     {aktuelle Schreibplane merken}
  3417.  
  3418.        MOV DX,3CEh
  3419.        MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  3420.        OUT DX,AX
  3421.  
  3422.        MOV BX,AX   {16 horizontale Punkte = 4 Bytes pro Zeile: BX:=4}
  3423.                    {(nutzt aus, dass AX zufaelligerweise gerade 4 ist)}
  3424.        MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  3425.  
  3426.        MOV CX,BX   {CX:=4}
  3427.        REP MOVSB   {1.Zeile zeichnen}
  3428.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3429.        MOV CX,BX
  3430.        REP MOVSB   {2.Zeile}
  3431.        ADD DI,AX
  3432.        MOV CX,BX
  3433.        REP MOVSB   {3.Zeile}
  3434.        ADD DI,AX
  3435.        MOV CX,BX
  3436.        REP MOVSB   {4.Zeile}
  3437.        ADD DI,AX
  3438.        MOV CX,BX
  3439.        REP MOVSB   {5.Zeile}
  3440.        ADD DI,AX
  3441.        MOV CX,BX
  3442.        REP MOVSB   {6.Zeile}
  3443.        ADD DI,AX
  3444.        MOV CX,BX
  3445.        REP MOVSB   {7.Zeile}
  3446.        ADD DI,AX
  3447.        MOV CX,BX
  3448.        REP MOVSB   {8.Zeile}
  3449.        ADD DI,AX
  3450.        MOV CX,BX
  3451.        REP MOVSB   {9.Zeile}
  3452.        ADD DI,AX
  3453.        MOV CX,BX
  3454.        REP MOVSB   {10.Zeile}
  3455.        ADD DI,AX
  3456.        MOV CX,BX
  3457.        REP MOVSB   {11.Zeile}
  3458.        ADD DI,AX
  3459.        MOV CX,BX
  3460.        REP MOVSB   {12.Zeile}
  3461.        ADD DI,AX
  3462.        MOV CX,BX
  3463.        REP MOVSB   {13.Zeile}
  3464.        ADD DI,AX
  3465.        MOV CX,BX
  3466.        REP MOVSB   {14.Zeile}
  3467.        ADD DI,AX
  3468.        MOV CX,BX
  3469.        REP MOVSB   {15.Zeile}
  3470.        ADD DI,AX
  3471.        MOV CX,BX
  3472.        REP MOVSB   {16.Zeile}
  3473.        ADD DI,AX
  3474.  
  3475.        MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  3476.        OUT DX,AX
  3477.  
  3478.        MOV DX,3C4h   {naechste Schreibplane:}
  3479.        POP AX
  3480.        SHL AH,1
  3481.        CMP AH,16
  3482.        JNE @nowrap1d
  3483.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3484.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3485.      @nowrap1d:
  3486.        OUT DX,AX
  3487.        PUSH AX
  3488.        SUB DI,16*LINESIZE   {DI wieder auf Ursprungsadresse zuruecksetzen}
  3489.        SUB SI,16*4          {SI auch}
  3490.  
  3491.  
  3492.        MOV AX,LINESIZE-4
  3493.        MOV CX,BX   {CX:=4}
  3494.        REP MOVSB   {1.Zeile zeichnen}
  3495.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3496.        MOV CX,BX
  3497.        REP MOVSB   {2.Zeile}
  3498.        ADD DI,AX
  3499.        MOV CX,BX
  3500.        REP MOVSB   {3.Zeile}
  3501.        ADD DI,AX
  3502.        MOV CX,BX
  3503.        REP MOVSB   {4.Zeile}
  3504.        ADD DI,AX
  3505.        MOV CX,BX
  3506.        REP MOVSB   {5.Zeile}
  3507.        ADD DI,AX
  3508.        MOV CX,BX
  3509.        REP MOVSB   {6.Zeile}
  3510.        ADD DI,AX
  3511.        MOV CX,BX
  3512.        REP MOVSB   {7.Zeile}
  3513.        ADD DI,AX
  3514.        MOV CX,BX
  3515.        REP MOVSB   {8.Zeile}
  3516.        ADD DI,AX
  3517.        MOV CX,BX
  3518.        REP MOVSB   {9.Zeile}
  3519.        ADD DI,AX
  3520.        MOV CX,BX
  3521.        REP MOVSB   {10.Zeile}
  3522.        ADD DI,AX
  3523.        MOV CX,BX
  3524.        REP MOVSB   {11.Zeile}
  3525.        ADD DI,AX
  3526.        MOV CX,BX
  3527.        REP MOVSB   {12.Zeile}
  3528.        ADD DI,AX
  3529.        MOV CX,BX
  3530.        REP MOVSB   {13.Zeile}
  3531.        ADD DI,AX
  3532.        MOV CX,BX
  3533.        REP MOVSB   {14.Zeile}
  3534.        ADD DI,AX
  3535.        MOV CX,BX
  3536.        REP MOVSB   {15.Zeile}
  3537.        ADD DI,AX
  3538.        MOV CX,BX
  3539.        REP MOVSB   {16.Zeile}
  3540.        ADD DI,AX
  3541.  
  3542.        POP AX
  3543.        SHL AH,1
  3544.        CMP AH,16
  3545.        JNE @nowrap2d
  3546.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3547.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3548.      @nowrap2d:
  3549.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3550.        PUSH AX
  3551.        MOV DX,3CEh
  3552.        MOV AX,0204h  {Leseplane 2 setzen}
  3553.        OUT DX,AX
  3554.        SUB DI,16*LINESIZE
  3555.        SUB SI,16*4
  3556.  
  3557.  
  3558.        MOV AX,LINESIZE-4
  3559.        MOV CX,BX   {CX:=4}
  3560.        REP MOVSB   {1.Zeile zeichnen}
  3561.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3562.        MOV CX,BX
  3563.        REP MOVSB   {2.Zeile}
  3564.        ADD DI,AX
  3565.        MOV CX,BX
  3566.        REP MOVSB   {3.Zeile}
  3567.        ADD DI,AX
  3568.        MOV CX,BX
  3569.        REP MOVSB   {4.Zeile}
  3570.        ADD DI,AX
  3571.        MOV CX,BX
  3572.        REP MOVSB   {5.Zeile}
  3573.        ADD DI,AX
  3574.        MOV CX,BX
  3575.        REP MOVSB   {6.Zeile}
  3576.        ADD DI,AX
  3577.        MOV CX,BX
  3578.        REP MOVSB   {7.Zeile}
  3579.        ADD DI,AX
  3580.        MOV CX,BX
  3581.        REP MOVSB   {8.Zeile}
  3582.        ADD DI,AX
  3583.        MOV CX,BX
  3584.        REP MOVSB   {9.Zeile}
  3585.        ADD DI,AX
  3586.        MOV CX,BX
  3587.        REP MOVSB   {10.Zeile}
  3588.        ADD DI,AX
  3589.        MOV CX,BX
  3590.        REP MOVSB   {11.Zeile}
  3591.        ADD DI,AX
  3592.        MOV CX,BX
  3593.        REP MOVSB   {12.Zeile}
  3594.        ADD DI,AX
  3595.        MOV CX,BX
  3596.        REP MOVSB   {13.Zeile}
  3597.        ADD DI,AX
  3598.        MOV CX,BX
  3599.        REP MOVSB   {14.Zeile}
  3600.        ADD DI,AX
  3601.        MOV CX,BX
  3602.        REP MOVSB   {15.Zeile}
  3603.        ADD DI,AX
  3604.        MOV CX,BX
  3605.        REP MOVSB   {16.Zeile}
  3606.        ADD DI,AX
  3607.  
  3608.        MOV AX,0304h
  3609.        OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  3610.        MOV DX,3C4h
  3611.        POP AX
  3612.        SHL AH,1
  3613.        CMP AH,16
  3614.        JNE @nowrap3d
  3615.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3616.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3617.      @nowrap3d:
  3618.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3619.        SUB DI,16*LINESIZE
  3620.        SUB SI,16*4
  3621.  
  3622.  
  3623.      @lastPlane4:
  3624.        MOV AX,LINESIZE-4
  3625.        MOV CX,BX   {CX:=4}
  3626.        REP MOVSB   {1.Zeile zeichnen}
  3627.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3628.        MOV CX,BX
  3629.        REP MOVSB   {2.Zeile}
  3630.        ADD DI,AX
  3631.        MOV CX,BX
  3632.        REP MOVSB   {3.Zeile}
  3633.        ADD DI,AX
  3634.        MOV CX,BX
  3635.        REP MOVSB   {4.Zeile}
  3636.        ADD DI,AX
  3637.        MOV CX,BX
  3638.        REP MOVSB   {5.Zeile}
  3639.        ADD DI,AX
  3640.        MOV CX,BX
  3641.        REP MOVSB   {6.Zeile}
  3642.        ADD DI,AX
  3643.        MOV CX,BX
  3644.        REP MOVSB   {7.Zeile}
  3645.        ADD DI,AX
  3646.        MOV CX,BX
  3647.        REP MOVSB   {8.Zeile}
  3648.        ADD DI,AX
  3649.        MOV CX,BX
  3650.        REP MOVSB   {9.Zeile}
  3651.        ADD DI,AX
  3652.        MOV CX,BX
  3653.        REP MOVSB   {10.Zeile}
  3654.        ADD DI,AX
  3655.        MOV CX,BX
  3656.        REP MOVSB   {11.Zeile}
  3657.        ADD DI,AX
  3658.        MOV CX,BX
  3659.        REP MOVSB   {12.Zeile}
  3660.        ADD DI,AX
  3661.        MOV CX,BX
  3662.        REP MOVSB   {13.Zeile}
  3663.        ADD DI,AX
  3664.        MOV CX,BX
  3665.        REP MOVSB   {14.Zeile}
  3666.        ADD DI,AX
  3667.        MOV CX,BX
  3668.        REP MOVSB   {15.Zeile}
  3669.        ADD DI,AX
  3670.        MOV CX,BX
  3671.        REP MOVSB   {16.Zeile}
  3672.  
  3673.  
  3674.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  3675.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  3676.        MOV AX,4005h
  3677.        MOV DX,3CEh
  3678.        OUT DX,AX
  3679.        {---}
  3680.  
  3681.        MOV AX,SEG @Data  {DS wiederherstellen}
  3682.        MOV DS,AX
  3683.  
  3684.     INC actIndex
  3685.     MOV AX,xtil
  3686.     INC AX
  3687.     MOV xtil,AX
  3688.     MOV DX,x
  3689.     ADD DX,16
  3690.     MOV x,DX
  3691.     CMP DX,XMAX+1-16
  3692.     JBE @repeat3
  3693.  
  3694.     INC ytil
  3695.     MOV AX,actIndex
  3696.     SUB AX,tiles
  3697.     ADD AX,XTiles
  3698.     MOV actIndex,AX
  3699.     MOV AX,y
  3700.     ADD AX,16
  3701.     MOV y,AX
  3702.     CMP AX,YMAX+1-16
  3703.     JBE @repeat2
  3704.  
  3705.     {Jetzt die untere rechte Tile - falls sie nicht bereits schon gezeichnet}
  3706.     {wurde: }
  3707.     CMP bottomcut,0
  3708.     JE @do_raender
  3709.     MOV DX,offsetXTiles
  3710.     MOV xt,DX
  3711.     MOV AX,ytil
  3712.     MOV yt,AX
  3713.     MOV CL,1
  3714.     OR AX,AX
  3715.     JS @go6
  3716.     CMP AX,YTiles
  3717.     JAE @go6
  3718.     DEC CL
  3719.   @go6:
  3720.     MOV offscreenFlag,CL
  3721.     CMP leftcut,0
  3722.     JE @label2
  3723.     XOR SI,SI
  3724.     DEC CL
  3725.     JZ @go7
  3726.     DEC DX  {DX=xt-1}
  3727.     JS @go7
  3728.     CMP DX,XTiles
  3729.     JAE @go7
  3730.     MOV SI,actIndex
  3731.     DEC SI
  3732.   @go7:
  3733.  
  3734.        {PROCEDURE DrawLowerLeftTile(y,leftcut,bottomcut:INTEGER; index:WORD);}
  3735.        { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
  3736.        {     leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  3737.        {     bottomcut = dto., unten}
  3738.        {     SI = index = Tilenummer}
  3739.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3740.        {rem: Tile wurde links und unten entsprechend geschnitten}
  3741.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  3742.        {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  3743.        {     bottomcut koennte auch ausgerechnet werden ueber:}
  3744.        {     bottomcut:=y+15-ymax}
  3745.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3746.        XOR AL,AL
  3747.  
  3748.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3749.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3750.        SHR AH,1    {rechtsschieben!}
  3751.        RCR AL,1
  3752.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  3753.  
  3754.        MOV DI,y    {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
  3755.        SHL DI,1
  3756.        MOV DI,CS:[OFFSET GADR + DI]
  3757.  
  3758.        MOV AX,leftcut
  3759.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  3760.        SHR AX,1
  3761.        SHR AX,1
  3762.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  3763.  
  3764.        MOV CX,16
  3765.        SUB CX,bottomcut  {CX:=16-bottomcut = zu zeichnende Zeilen}
  3766.  
  3767.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  3768.        {verwendet werden!}
  3769.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  3770.        MOV BP,16+3
  3771.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  3772.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  3773.  
  3774.  
  3775.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3776.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3777.  
  3778.        MOV DX,3CEh
  3779.        AND BL,3
  3780.        MOV AH,BL   {AH:=leftcut mod 4}
  3781.        MOV AL,4
  3782.  
  3783.        JNE @mode0e {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  3784.  
  3785.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  3786.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  3787.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  3788.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  3789.        MOV AX,4105h
  3790.        OUT DX,AX   {WriteMode 1 waehlen}
  3791.        MOV DX,3C4h
  3792.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  3793.        OUT DX,AX
  3794.        JMP @lastPlane5  {abkuerzen}
  3795.        {---}
  3796.  
  3797.      @mode0e:
  3798.        OUT DX,AX   {aktuelle Leseplane waehlen}
  3799.        PUSH AX     {und fuer spaeter merken}
  3800.  
  3801.        MOV DX,3C4h
  3802.        MOV AX,0102h    {Schreibplane 0 waehlen}
  3803.        OUT DX,AX
  3804.  
  3805.        MOV BX,BP
  3806.        SHR BX,1
  3807.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  3808.  
  3809.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3810.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  3811.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3812.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  3813.  
  3814.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3815.        PUSH DI
  3816.        PUSH BP     {BP retten}
  3817.        PUSH CX     {CX = Zeilenzaehler retten}
  3818.        MOV BP,CX   {BP:=Zeilenzaehler}
  3819.      @eineZeile1d:
  3820.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3821.        REP MOVSB   {eine Zeile uebertragen}
  3822.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3823.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3824.        DEC BP
  3825.        JNZ @eineZeile1d
  3826.        POP CX
  3827.        POP BP
  3828.        POP DI
  3829.        POP SI
  3830.  
  3831.        MOV DX,3C4h
  3832.        MOV AX,0202h  {Schreibplane 1 waehlen}
  3833.        OUT DX,AX
  3834.  
  3835.        MOV DX,3CEh   {naechste Leseplane:}
  3836.        POP AX
  3837.        INC AH
  3838.        AND AH,3      {um 1 erhoehen MOD 4}
  3839.        JNE @nowrap1e
  3840.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  3841.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  3842.      @nowrap1e:
  3843.        OUT DX,AX
  3844.        PUSH AX
  3845.  
  3846.  
  3847.        DEC BP        {BP:=16+2-leftcut}
  3848.        MOV BX,BP
  3849.        SHR BX,1
  3850.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  3851.  
  3852.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3853.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  3854.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3855.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  3856.  
  3857.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3858.        PUSH DI
  3859.        PUSH BP     {BP retten}
  3860.        PUSH CX     {CX = Zeilenzaehler retten}
  3861.        MOV BP,CX   {BP:=Zeilenzaehler}
  3862.      @eineZeile2d:
  3863.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3864.        REP MOVSB   {eine Zeile uebertragen}
  3865.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3866.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3867.        DEC BP
  3868.        JNZ @eineZeile2d
  3869.        POP CX
  3870.        POP BP
  3871.        POP DI
  3872.        POP SI
  3873.  
  3874.        MOV DX,3C4h
  3875.        MOV AX,0402h  {Schreibplane 2 waehlen}
  3876.        OUT DX,AX
  3877.  
  3878.        MOV DX,3CEh   {naechste Leseplane:}
  3879.        POP AX
  3880.        INC AH
  3881.        AND AH,3      {um 1 erhoehen MOD 4}
  3882.        JNE @nowrap2e
  3883.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  3884.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  3885.      @nowrap2e:
  3886.        OUT DX,AX
  3887.        PUSH AX
  3888.  
  3889.  
  3890.        DEC BP        {BP:=16+1-leftcut}
  3891.        MOV BX,BP
  3892.        SHR BX,1
  3893.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  3894.  
  3895.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3896.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  3897.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3898.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  3899.  
  3900.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3901.        PUSH DI
  3902.        PUSH BP     {BP retten}
  3903.        PUSH CX     {CX = Zeilenzaehler retten}
  3904.        MOV BP,CX   {BP:=Zeilenzaehler}
  3905.      @eineZeile3d:
  3906.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3907.        REP MOVSB   {eine Zeile uebertragen}
  3908.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3909.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3910.        DEC BP
  3911.        JNZ @eineZeile3d
  3912.        POP CX
  3913.        POP BP
  3914.        POP DI
  3915.        POP SI
  3916.  
  3917.        MOV DX,3C4h
  3918.        MOV AX,0802h  {Schreibplane 3 waehlen}
  3919.        OUT DX,AX
  3920.  
  3921.        MOV DX,3CEh   {naechste Leseplane:}
  3922.        POP AX
  3923.        INC AH
  3924.        AND AH,3      {um 1 erhoehen MOD 4}
  3925.        JNE @nowrap3e
  3926.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  3927.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  3928.      @nowrap3e:
  3929.        OUT DX,AX
  3930.                      {Wert nicht mehr pushen!}
  3931.  
  3932.  
  3933.        DEC BP        {BP:=16-leftcut}
  3934.      @lastplane5:
  3935.                      {BP direkt verwenden}
  3936.        SHR BP,1
  3937.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  3938.  
  3939.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3940.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3941.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3942.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3943.  
  3944.        MOV BX,CX   {BX:=Zeilenzaehler}
  3945.      @eineZeile4d:
  3946.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  3947.        REP MOVSB   {eine Zeile uebertragen}
  3948.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3949.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3950.        DEC BX
  3951.        JNZ @eineZeile4d
  3952.  
  3953.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  3954.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  3955.        MOV AX,4005h
  3956.        MOV DX,3CEh
  3957.        OUT DX,AX
  3958.        {---}
  3959.  
  3960.        POP BP
  3961.        MOV AX,SEG @Data  {DS wiederherstellen}
  3962.        MOV DS,AX
  3963.  
  3964.   @label2:
  3965.     MOV AX,xpix
  3966.     MOV x,AX
  3967.  
  3968.     {Jetzt die unteren Tiles, die nicht seitlich abgeschnitten sind:}
  3969.     @repeat4:
  3970.       MOV CL,offscreenFlag
  3971.       XOR SI,SI
  3972.       DEC CL
  3973.       JZ @go8
  3974.       MOV AX,xt
  3975.       OR AX,AX
  3976.       JS @go8
  3977.       CMP AX,XTiles
  3978.       JAE @go8
  3979.       MOV SI,actIndex
  3980.     @go8:
  3981.  
  3982.          {PROCEDURE DrawLowerTile(x,y,bottomcut:INTEGER; index:WORD);}
  3983.          { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  3984.          {     bottomcut = Anzahl der unten abzuschneidenden Tile-Zeilen}
  3985.          {     SI = index = Tilenummer}
  3986.          {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3987.          {rem: Tile wurde unten entsprechend geschnitten}
  3988.          {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten!}
  3989.          {     bottomcut koennte auch ausgerechnet werden ueber:}
  3990.          {     bottomcut:=y+15-ymax}
  3991.          MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3992.          XOR AL,AL
  3993.  
  3994.          SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3995.          RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3996.          SHR AH,1    {rechtsschieben!}
  3997.          RCR AL,1
  3998.          MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  3999.  
  4000.          MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  4001.          SHL DI,1
  4002.          MOV DI,CS:[OFFSET GADR + DI]
  4003.          MOV AX,x
  4004.          MOV BX,AX   {Kopie von X in BX aufbewahren}
  4005.          SHR AX,1
  4006.          SHR AX,1
  4007.          ADD DI,AX
  4008.  
  4009.          MOV CX,16
  4010.          SUB CX,bottomcut  {CX:=zu zeichnende Zeilenzahl = 16-bottomcut}
  4011.  
  4012.          {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4013.          {verwendet werden!}
  4014.          PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4015.          MOV BP,CX
  4016.          SHL BP,1
  4017.          SHL BP,1    {BP := (zu zeichnende Zeilen)*4 }
  4018.  
  4019.          MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4020.          MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4021.  
  4022.          MOV DX,3C4h
  4023.          MOV AL,2
  4024.          AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  4025.          JNE @mode0f {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  4026.  
  4027.          {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  4028.          MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  4029.          OUT DX,AX
  4030.          MOV AX,4105h
  4031.          MOV DX,3CEh
  4032.          OUT DX,AX   {WriteMode 1 waehlen}
  4033.          MOV BX,CX   {BX:=CX=zu zeichnende Zeilen}
  4034.          JMP @lastPlane6  {abkuerzen}
  4035.          {---}
  4036.  
  4037.        @mode0f:
  4038.          MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  4039.          OUT DX,AX
  4040.          PUSH AX     {aktuelle Schreibplane merken}
  4041.  
  4042.          MOV DX,3CEh
  4043.          MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  4044.          OUT DX,AX
  4045.  
  4046.          MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  4047.          MOV BX,CX   {zu zeichnende Zeilenzahl nach BX retten}
  4048.        @eineZeile1e:
  4049.          MOVSB
  4050.          MOVSB
  4051.          MOVSB
  4052.          MOVSB
  4053.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4054.          LOOP @eineZeile1e
  4055.  
  4056.          MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  4057.          OUT DX,AX
  4058.  
  4059.          MOV DX,3C4h   {naechste Schreibplane:}
  4060.          POP AX
  4061.          SHL AH,1
  4062.          CMP AH,16
  4063.          JNE @nowrap1f
  4064.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4065.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4066.        @nowrap1f:
  4067.          OUT DX,AX
  4068.          PUSH AX
  4069.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4070.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4071.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4072.          SUB SI,BP     {SI auch zuruecksetzen}
  4073.  
  4074.  
  4075.          MOV AX,LINESIZE-4
  4076.          MOV CX,BX   {CX:=zu zeichnende Zeilenanzahl}
  4077.        @eineZeile2e:
  4078.          MOVSB
  4079.          MOVSB
  4080.          MOVSB
  4081.          MOVSB
  4082.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4083.          LOOP @eineZeile2e
  4084.  
  4085.          POP AX
  4086.          SHL AH,1
  4087.          CMP AH,16
  4088.          JNE @nowrap2f
  4089.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4090.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4091.        @nowrap2f:
  4092.          OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  4093.          PUSH AX
  4094.          MOV DX,3CEh
  4095.          MOV AX,0204h  {Leseplane 2 setzen}
  4096.          OUT DX,AX
  4097.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4098.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4099.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4100.          SUB SI,BP     {SI auch zuruecksetzen}
  4101.  
  4102.  
  4103.          MOV AX,LINESIZE-4
  4104.          MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  4105.        @eineZeile3e:
  4106.          MOVSB
  4107.          MOVSB
  4108.          MOVSB
  4109.          MOVSB
  4110.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4111.          LOOP @eineZeile3e
  4112.  
  4113.          MOV AX,0304h
  4114.          OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  4115.          MOV DX,3C4h
  4116.          POP AX
  4117.          SHL AH,1
  4118.          CMP AH,16
  4119.          JNE @nowrap3f
  4120.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4121.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4122.        @nowrap3f:
  4123.          OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  4124.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4125.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4126.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4127.          SUB SI,BP     {SI auch zuruecksetzen}
  4128.  
  4129.  
  4130.        @lastPlane6:
  4131.          MOV AX,LINESIZE-4
  4132.          MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  4133.        @eineZeile4e:
  4134.          MOVSB
  4135.          MOVSB
  4136.          MOVSB
  4137.          MOVSB
  4138.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4139.          LOOP @eineZeile4e
  4140.  
  4141.          {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  4142.          {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  4143.          MOV AX,4005h
  4144.          MOV DX,3CEh
  4145.          OUT DX,AX
  4146.          {---}
  4147.  
  4148.          POP BP
  4149.          MOV AX,SEG @Data  {DS wiederherstellen}
  4150.          MOV DS,AX
  4151.  
  4152.     INC xt
  4153.     INC actIndex
  4154.     MOV AX,x
  4155.     ADD AX,16
  4156.     MOV x,AX
  4157.     CMP AX,XMAX+1-16
  4158.     JBE @repeat4
  4159.  
  4160.     {Jetzt evtl. noch die untere rechte Eck-Tile:}
  4161.     CMP AX,XMAX+1
  4162.     JE @do_raender
  4163.     MOV CL,offscreenFlag
  4164.     XOR SI,SI
  4165.     DEC CL
  4166.     JZ @go9
  4167.     MOV AX,xt
  4168.     OR AX,AX
  4169.     JS @go9
  4170.     CMP AX,XTiles
  4171.     JAE @go9
  4172.     MOV SI,actIndex
  4173.   @go9:
  4174.  
  4175.        {PROCEDURE DrawLowerRightTile(x,y,rightcut,bottomcut:INTEGER; index:WORD);}
  4176.        { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  4177.        {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  4178.        {     bottomcut = dto., unten}
  4179.        {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  4180.        {     bottomcut koennte auch ausgerechnet werden ueber:}
  4181.        {     bottomcut:=y+15-ymax}
  4182.        {     SI = index = Tilenummer}
  4183.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4184.        {rem: Tile wurde rechts und unten entsprechend geschnitten}
  4185.        {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  4186.        {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  4187.        {     rightcut := x+15-xmax }
  4188.        {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  4189.        {     bottomcut koennte auch ausgerechnet werden ueber:}
  4190.        {     bottomcut:=y+15-ymax}
  4191.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4192.        XOR AL,AL
  4193.  
  4194.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4195.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4196.        SHR AH,1    {rechtsschieben!}
  4197.        RCR AL,1
  4198.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4199.  
  4200.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  4201.        SHL DI,1
  4202.        MOV DI,CS:[OFFSET GADR + DI]
  4203.        MOV AX,x
  4204.        MOV BX,AX   {Kopie von x nach BX}
  4205.        SHR AX,1
  4206.        SHR AX,1
  4207.        ADD DI,AX
  4208.  
  4209.        MOV AX,rightcut
  4210.        MOV CX,16
  4211.        SUB CX,bottomcut  {CX:=16-bottomcut = zu zeichnende Zeilen}
  4212.  
  4213.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4214.        {verwendet werden!}
  4215.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4216.        MOV BP,16+3
  4217.        SUB BP,AX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  4218.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  4219.        MOV AH,AL   {rightcut nach AH retten}
  4220.  
  4221.  
  4222.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4223.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4224.  
  4225.        MOV DX,3C4h
  4226.        MOV AL,2
  4227.        AND BX,3
  4228.  
  4229.        JNE @mode0g {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  4230.        AND AH,3    {wir WriteMode1 verwenden!}
  4231.        JNE @mode0g
  4232.  
  4233.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  4234.        MOV AH,0Fh
  4235.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  4236.        MOV DX,3CEh
  4237.        MOV AX,4105h {WriteMode 1 waehlen}
  4238.        OUT DX,AX
  4239.        SUB BP,3     {BP auf die richtige Groesse bringen}
  4240.        JMP @lastPlane7  {abkuerzen}
  4241.        {---}
  4242.  
  4243.      @mode0g:
  4244.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  4245.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  4246.        PUSH AX     {und fuer spaeter merken}
  4247.  
  4248.        MOV DX,3CEh
  4249.        MOV AX,0004h    {Leseplane 0 waehlen}
  4250.        OUT DX,AX
  4251.  
  4252.        MOV BX,BP
  4253.        SHR BX,1
  4254.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  4255.  
  4256.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4257.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  4258.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4259.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  4260.  
  4261.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4262.        PUSH DI
  4263.        PUSH BP     {BP retten}
  4264.        PUSH CX     {CX = Zeilenzaehler retten}
  4265.        MOV BP,CX   {BP:=Zeilenzaehler}
  4266.      @eineZeile1f:
  4267.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4268.        REP MOVSB   {eine Zeile uebertragen}
  4269.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4270.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4271.        DEC BP
  4272.        JNZ @eineZeile1f
  4273.        POP CX
  4274.        POP BP
  4275.        POP DI
  4276.        POP SI
  4277.  
  4278.  
  4279.        MOV DX,3CEh
  4280.        MOV AX,0104h  {Leseplane 1 waehlen}
  4281.        OUT DX,AX
  4282.  
  4283.        MOV DX,3C4h   {naechste Schreibplane:}
  4284.        POP AX
  4285.        SHL AH,1
  4286.        CMP AH,16
  4287.        JNE @nowrap1g
  4288.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4289.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4290.      @nowrap1g:
  4291.        OUT DX,AX
  4292.        PUSH AX
  4293.  
  4294.  
  4295.        DEC BP        {BP:=16+2-rightcut}
  4296.        MOV BX,BP
  4297.        SHR BX,1
  4298.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  4299.  
  4300.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4301.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  4302.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4303.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  4304.  
  4305.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4306.        PUSH DI
  4307.        PUSH BP     {BP retten}
  4308.        PUSH CX     {CX = Zeilenzaehler retten}
  4309.        MOV BP,CX   {BP:=Zeilenzaehler}
  4310.      @eineZeile2f:
  4311.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4312.        REP MOVSB   {eine Zeile uebertragen}
  4313.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4314.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4315.        DEC BP
  4316.        JNZ @eineZeile2f
  4317.        POP CX
  4318.        POP BP
  4319.        POP DI
  4320.        POP SI
  4321.  
  4322.  
  4323.        MOV DX,3CEh
  4324.        MOV AX,0204h  {Leseplane 2 waehlen}
  4325.        OUT DX,AX
  4326.  
  4327.        MOV DX,3C4h   {naechste Schreibplane:}
  4328.        POP AX
  4329.        SHL AH,1
  4330.        CMP AH,16
  4331.        JNE @nowrap2g
  4332.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4333.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4334.      @nowrap2g:
  4335.        OUT DX,AX
  4336.        PUSH AX
  4337.  
  4338.  
  4339.        DEC BP        {BP:=16+1-rightcut}
  4340.        MOV BX,BP
  4341.        SHR BX,1
  4342.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  4343.  
  4344.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4345.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  4346.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4347.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  4348.  
  4349.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4350.        PUSH DI
  4351.        PUSH BP     {BP retten}
  4352.        PUSH CX     {CX = Zeilenzaehler retten}
  4353.        MOV BP,CX   {BP:=Zeilenzaehler}
  4354.      @eineZeile3f:
  4355.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4356.        REP MOVSB   {eine Zeile uebertragen}
  4357.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4358.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4359.        DEC BP
  4360.        JNZ @eineZeile3f
  4361.        POP CX
  4362.        POP BP
  4363.        POP DI
  4364.        POP SI
  4365.  
  4366.  
  4367.        MOV DX,3CEh
  4368.        MOV AX,0304h  {Leseplane 3 waehlen}
  4369.        OUT DX,AX
  4370.  
  4371.        MOV DX,3C4h   {naechste Schreibplane:}
  4372.        POP AX
  4373.        SHL AH,1
  4374.        CMP AH,16
  4375.        JNE @nowrap3g
  4376.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4377.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4378.      @nowrap3g:
  4379.        OUT DX,AX
  4380.                      {Wert nicht mehr pushen!}
  4381.  
  4382.  
  4383.        DEC BP        {BP:=16-rightcut}
  4384.      @lastplane7:
  4385.                      {BP direkt verwenden}
  4386.        SHR BP,1
  4387.        SHR BP,1      {BX:=Bytes_je_Plane3_Zeile}
  4388.  
  4389.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4390.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4391.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4392.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4393.  
  4394.        MOV BX,CX   {BX:=Zeilenzaehler}
  4395.      @eineZeile4g:
  4396.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  4397.        REP MOVSB   {eine Zeile uebertragen}
  4398.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4399.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4400.        DEC BX
  4401.        JNZ @eineZeile4g
  4402.  
  4403.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  4404.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  4405.        MOV AX,4005h
  4406.        MOV DX,3CEh
  4407.        OUT DX,AX
  4408.        {---}
  4409.  
  4410.        POP BP
  4411.        MOV AX,SEG @Data  {DS wiederherstellen}
  4412.        MOV DS,AX
  4413.  
  4414.   {Nun noch die Kacheln links und/oder rechts entlang des Bildschirmrandes:}
  4415.   @do_raender:
  4416.     CMP leftcut,0  {oder rightcut, denn da 320 durch 16 teilbar ist,}
  4417.     JE @ende       {ist leftcut=0  <=>  rightcut=0 }
  4418.  
  4419.     MOV AX,offsetXTiles
  4420.     DEC AX
  4421.     MOV xt,AX
  4422.     MOV AX,ypix
  4423.     MOV y,AX
  4424.     INC tiles
  4425.     MOV AX,offsetYTiles
  4426.     MOV yt,AX
  4427.  
  4428.   @repeat5:
  4429.     MOV CL,1
  4430.     OR AX,AX
  4431.     JS @go10
  4432.     CMP AX,YTiles
  4433.     JAE @go10
  4434.     DEC CL
  4435.   @go10:
  4436.     MOV offscreenFlag,CL
  4437.     XOR SI,SI
  4438.     DEC CL
  4439.     JZ @go11
  4440.     MOV AX,xt
  4441.     OR AX,AX
  4442.     JS @go11
  4443.     CMP AX,XTiles
  4444.     JAE @go11
  4445.     MOV SI,RandIndex
  4446.   @go11:
  4447.  
  4448.  
  4449.        {PROCEDURE DrawLeftTile(y,leftcut:INTEGER; index:WORD);}
  4450.        { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
  4451.        {     leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  4452.        {     SI = index = Tilenummer}
  4453.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4454.        {rem: Tile wurde links entsprechend geschnitten}
  4455.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  4456.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4457.        XOR AL,AL
  4458.  
  4459.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4460.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4461.        SHR AH,1    {rechtsschieben!}
  4462.        RCR AL,1
  4463.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4464.  
  4465.        MOV DI,y    {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
  4466.        SHL DI,1
  4467.        MOV DI,CS:[OFFSET GADR + DI]
  4468.  
  4469.        MOV AX,leftcut
  4470.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  4471.        SHR AX,1
  4472.        SHR AX,1
  4473.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  4474.  
  4475.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4476.        {verwendet werden!}
  4477.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4478.        MOV BP,16+3
  4479.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  4480.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  4481.  
  4482.  
  4483.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4484.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4485.  
  4486.        MOV DX,3CEh
  4487.        AND BL,3
  4488.        MOV AH,BL   {AH:=leftcut mod 4}
  4489.        MOV AL,4
  4490.  
  4491.        JNE @mode0h {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  4492.  
  4493.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  4494.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  4495.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  4496.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  4497.        MOV AX,4105h
  4498.        OUT DX,AX   {WriteMode 1 waehlen}
  4499.        MOV DX,3C4h
  4500.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  4501.        OUT DX,AX
  4502.        JMP @lastPlane8  {abkuerzen}
  4503.        {---}
  4504.  
  4505.      @mode0h:
  4506.        OUT DX,AX   {aktuelle Leseplane waehlen}
  4507.        PUSH AX     {und fuer spaeter merken}
  4508.  
  4509.        MOV DX,3C4h
  4510.        MOV AX,0102h    {Schreibplane 0 waehlen}
  4511.        OUT DX,AX
  4512.  
  4513.        MOV BX,BP
  4514.        SHR BX,1
  4515.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  4516.  
  4517.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4518.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  4519.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4520.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  4521.  
  4522.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4523.        REP MOVSB   {1.Zeile}
  4524.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4525.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4526.        MOV CX,BX
  4527.        REP MOVSB   {2.Zeile}
  4528.        ADD DI,AX
  4529.        ADD SI,DX
  4530.        MOV CX,BX
  4531.        REP MOVSB   {3.Zeile}
  4532.        ADD DI,AX
  4533.        ADD SI,DX
  4534.        MOV CX,BX
  4535.        REP MOVSB   {4.Zeile}
  4536.        ADD DI,AX
  4537.        ADD SI,DX
  4538.        MOV CX,BX
  4539.        REP MOVSB   {5.Zeile}
  4540.        ADD DI,AX
  4541.        ADD SI,DX
  4542.        MOV CX,BX
  4543.        REP MOVSB   {6.Zeile}
  4544.        ADD DI,AX
  4545.        ADD SI,DX
  4546.        MOV CX,BX
  4547.        REP MOVSB   {7.Zeile}
  4548.        ADD DI,AX
  4549.        ADD SI,DX
  4550.        MOV CX,BX
  4551.        REP MOVSB   {8.Zeile}
  4552.        ADD DI,AX
  4553.        ADD SI,DX
  4554.        MOV CX,BX
  4555.        REP MOVSB   {9.Zeile}
  4556.        ADD DI,AX
  4557.        ADD SI,DX
  4558.        MOV CX,BX
  4559.        REP MOVSB   {10.Zeile}
  4560.        ADD DI,AX
  4561.        ADD SI,DX
  4562.        MOV CX,BX
  4563.        REP MOVSB   {11.Zeile}
  4564.        ADD DI,AX
  4565.        ADD SI,DX
  4566.        MOV CX,BX
  4567.        REP MOVSB   {12.Zeile}
  4568.        ADD DI,AX
  4569.        ADD SI,DX
  4570.        MOV CX,BX
  4571.        REP MOVSB   {13.Zeile}
  4572.        ADD DI,AX
  4573.        ADD SI,DX
  4574.        MOV CX,BX
  4575.        REP MOVSB   {14.Zeile}
  4576.        ADD DI,AX
  4577.        ADD SI,DX
  4578.        MOV CX,BX
  4579.        REP MOVSB   {15.Zeile}
  4580.        ADD DI,AX
  4581.        ADD SI,DX
  4582.        MOV CX,BX
  4583.        REP MOVSB   {16.Zeile}
  4584.        ADD DI,AX
  4585.        ADD SI,DX
  4586.  
  4587.  
  4588.        MOV DX,3C4h
  4589.        MOV AX,0202h  {Schreibplane 1 waehlen}
  4590.        OUT DX,AX
  4591.  
  4592.        MOV DX,3CEh   {naechste Leseplane:}
  4593.        POP AX
  4594.        INC AH
  4595.        AND AH,3      {um 1 erhoehen MOD 4}
  4596.        JNE @nowrap1h
  4597.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4598.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4599.      @nowrap1h:
  4600.        OUT DX,AX
  4601.        PUSH AX
  4602.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  4603.        SUB SI,16*4
  4604.  
  4605.  
  4606.        DEC BP        {BP:=16+2-leftcut}
  4607.        MOV BX,BP
  4608.        SHR BX,1
  4609.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  4610.  
  4611.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4612.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  4613.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4614.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  4615.  
  4616.        MOV CX,BX   {CX:=Bytes_je_Plane1_Zeile}
  4617.        REP MOVSB   {1.Zeile}
  4618.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4619.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4620.        MOV CX,BX
  4621.        REP MOVSB   {2.Zeile}
  4622.        ADD DI,AX
  4623.        ADD SI,DX
  4624.        MOV CX,BX
  4625.        REP MOVSB   {3.Zeile}
  4626.        ADD DI,AX
  4627.        ADD SI,DX
  4628.        MOV CX,BX
  4629.        REP MOVSB   {4.Zeile}
  4630.        ADD DI,AX
  4631.        ADD SI,DX
  4632.        MOV CX,BX
  4633.        REP MOVSB   {5.Zeile}
  4634.        ADD DI,AX
  4635.        ADD SI,DX
  4636.        MOV CX,BX
  4637.        REP MOVSB   {6.Zeile}
  4638.        ADD DI,AX
  4639.        ADD SI,DX
  4640.        MOV CX,BX
  4641.        REP MOVSB   {7.Zeile}
  4642.        ADD DI,AX
  4643.        ADD SI,DX
  4644.        MOV CX,BX
  4645.        REP MOVSB   {8.Zeile}
  4646.        ADD DI,AX
  4647.        ADD SI,DX
  4648.        MOV CX,BX
  4649.        REP MOVSB   {9.Zeile}
  4650.        ADD DI,AX
  4651.        ADD SI,DX
  4652.        MOV CX,BX
  4653.        REP MOVSB   {10.Zeile}
  4654.        ADD DI,AX
  4655.        ADD SI,DX
  4656.        MOV CX,BX
  4657.        REP MOVSB   {11.Zeile}
  4658.        ADD DI,AX
  4659.        ADD SI,DX
  4660.        MOV CX,BX
  4661.        REP MOVSB   {12.Zeile}
  4662.        ADD DI,AX
  4663.        ADD SI,DX
  4664.        MOV CX,BX
  4665.        REP MOVSB   {13.Zeile}
  4666.        ADD DI,AX
  4667.        ADD SI,DX
  4668.        MOV CX,BX
  4669.        REP MOVSB   {14.Zeile}
  4670.        ADD DI,AX
  4671.        ADD SI,DX
  4672.        MOV CX,BX
  4673.        REP MOVSB   {15.Zeile}
  4674.        ADD DI,AX
  4675.        ADD SI,DX
  4676.        MOV CX,BX
  4677.        REP MOVSB   {16.Zeile}
  4678.        ADD DI,AX
  4679.        ADD SI,DX
  4680.  
  4681.  
  4682.        MOV DX,3C4h
  4683.        MOV AX,0402h  {Schreibplane 2 waehlen}
  4684.        OUT DX,AX
  4685.  
  4686.        MOV DX,3CEh   {naechste Leseplane:}
  4687.        POP AX
  4688.        INC AH
  4689.        AND AH,3      {um 1 erhoehen MOD 4}
  4690.        JNE @nowrap2h
  4691.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4692.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4693.      @nowrap2h:
  4694.        OUT DX,AX
  4695.        PUSH AX
  4696.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  4697.        SUB SI,16*4
  4698.  
  4699.  
  4700.        DEC BP        {BP:=16+1-leftcut}
  4701.        MOV BX,BP
  4702.        SHR BX,1
  4703.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  4704.  
  4705.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4706.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  4707.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4708.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  4709.  
  4710.        MOV CX,BX   {CX:=Bytes_je_Plane2_Zeile}
  4711.        REP MOVSB   {1.Zeile}
  4712.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4713.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4714.        MOV CX,BX
  4715.        REP MOVSB   {2.Zeile}
  4716.        ADD DI,AX
  4717.        ADD SI,DX
  4718.        MOV CX,BX
  4719.        REP MOVSB   {3.Zeile}
  4720.        ADD DI,AX
  4721.        ADD SI,DX
  4722.        MOV CX,BX
  4723.        REP MOVSB   {4.Zeile}
  4724.        ADD DI,AX
  4725.        ADD SI,DX
  4726.        MOV CX,BX
  4727.        REP MOVSB   {5.Zeile}
  4728.        ADD DI,AX
  4729.        ADD SI,DX
  4730.        MOV CX,BX
  4731.        REP MOVSB   {6.Zeile}
  4732.        ADD DI,AX
  4733.        ADD SI,DX
  4734.        MOV CX,BX
  4735.        REP MOVSB   {7.Zeile}
  4736.        ADD DI,AX
  4737.        ADD SI,DX
  4738.        MOV CX,BX
  4739.        REP MOVSB   {8.Zeile}
  4740.        ADD DI,AX
  4741.        ADD SI,DX
  4742.        MOV CX,BX
  4743.        REP MOVSB   {9.Zeile}
  4744.        ADD DI,AX
  4745.        ADD SI,DX
  4746.        MOV CX,BX
  4747.        REP MOVSB   {10.Zeile}
  4748.        ADD DI,AX
  4749.        ADD SI,DX
  4750.        MOV CX,BX
  4751.        REP MOVSB   {11.Zeile}
  4752.        ADD DI,AX
  4753.        ADD SI,DX
  4754.        MOV CX,BX
  4755.        REP MOVSB   {12.Zeile}
  4756.        ADD DI,AX
  4757.        ADD SI,DX
  4758.        MOV CX,BX
  4759.        REP MOVSB   {13.Zeile}
  4760.        ADD DI,AX
  4761.        ADD SI,DX
  4762.        MOV CX,BX
  4763.        REP MOVSB   {14.Zeile}
  4764.        ADD DI,AX
  4765.        ADD SI,DX
  4766.        MOV CX,BX
  4767.        REP MOVSB   {15.Zeile}
  4768.        ADD DI,AX
  4769.        ADD SI,DX
  4770.        MOV CX,BX
  4771.        REP MOVSB   {16.Zeile}
  4772.        ADD DI,AX
  4773.        ADD SI,DX
  4774.  
  4775.  
  4776.        MOV DX,3C4h
  4777.        MOV AX,0802h  {Schreibplane 3 waehlen}
  4778.        OUT DX,AX
  4779.  
  4780.        MOV DX,3CEh   {naechste Leseplane:}
  4781.        POP AX
  4782.        INC AH
  4783.        AND AH,3      {um 1 erhoehen MOD 4}
  4784.        JNE @nowrap3h
  4785.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4786.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4787.      @nowrap3h:
  4788.        OUT DX,AX
  4789.                      {Wert nicht mehr pushen!}
  4790.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  4791.        SUB SI,16*4
  4792.  
  4793.  
  4794.  
  4795.        DEC BP        {BP:=16-leftcut}
  4796.      @lastplane8:
  4797.                      {BP direkt verwenden}
  4798.        SHR BP,1
  4799.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  4800.  
  4801.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4802.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4803.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4804.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4805.  
  4806.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  4807.        REP MOVSB   {1.Zeile}
  4808.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4809.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4810.        MOV CX,BP
  4811.        REP MOVSB   {2.Zeile}
  4812.        ADD DI,AX
  4813.        ADD SI,DX
  4814.        MOV CX,BP
  4815.        REP MOVSB   {3.Zeile}
  4816.        ADD DI,AX
  4817.        ADD SI,DX
  4818.        MOV CX,BP
  4819.        REP MOVSB   {4.Zeile}
  4820.        ADD DI,AX
  4821.        ADD SI,DX
  4822.        MOV CX,BP
  4823.        REP MOVSB   {5.Zeile}
  4824.        ADD DI,AX
  4825.        ADD SI,DX
  4826.        MOV CX,BP
  4827.        REP MOVSB   {6.Zeile}
  4828.        ADD DI,AX
  4829.        ADD SI,DX
  4830.        MOV CX,BP
  4831.        REP MOVSB   {7.Zeile}
  4832.        ADD DI,AX
  4833.        ADD SI,DX
  4834.        MOV CX,BP
  4835.        REP MOVSB   {8.Zeile}
  4836.        ADD DI,AX
  4837.        ADD SI,DX
  4838.        MOV CX,BP
  4839.        REP MOVSB   {9.Zeile}
  4840.        ADD DI,AX
  4841.        ADD SI,DX
  4842.        MOV CX,BP
  4843.        REP MOVSB   {10.Zeile}
  4844.        ADD DI,AX
  4845.        ADD SI,DX
  4846.        MOV CX,BP
  4847.        REP MOVSB   {11.Zeile}
  4848.        ADD DI,AX
  4849.        ADD SI,DX
  4850.        MOV CX,BP
  4851.        REP MOVSB   {12.Zeile}
  4852.        ADD DI,AX
  4853.        ADD SI,DX
  4854.        MOV CX,BP
  4855.        REP MOVSB   {13.Zeile}
  4856.        ADD DI,AX
  4857.        ADD SI,DX
  4858.        MOV CX,BP
  4859.        REP MOVSB   {14.Zeile}
  4860.        ADD DI,AX
  4861.        ADD SI,DX
  4862.        MOV CX,BP
  4863.        REP MOVSB   {15.Zeile}
  4864.        ADD DI,AX
  4865.        ADD SI,DX
  4866.        MOV CX,BP
  4867.        REP MOVSB   {16.Zeile}
  4868.  
  4869.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  4870.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  4871.        MOV AX,4005h
  4872.        MOV DX,3CEh
  4873.        OUT DX,AX
  4874.        {---}
  4875.  
  4876.        POP BP
  4877.        MOV AX,SEG @Data  {DS wiederherstellen}
  4878.        MOV DS,AX
  4879.  
  4880.     MOV CL,offscreenFlag
  4881.     XOR SI,SI
  4882.     DEC CL
  4883.     JZ @go12
  4884.     MOV AX,xt
  4885.     MOV DX,tiles
  4886.     ADD AX,DX
  4887.     JS @go12
  4888.     CMP AX,XTiles
  4889.     JAE @go12
  4890.     MOV SI,RandIndex
  4891.     ADD SI,DX
  4892.   @go12:
  4893.  
  4894.  
  4895.        {PROCEDURE DrawRightTile(x,y,rightcut:INTEGER; index:WORD);}
  4896.        { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  4897.        {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  4898.        {     SI = index = Tilenummer}
  4899.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4900.        {rem: Tile wurde rechts entsprechend geschnitten}
  4901.        {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  4902.        {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  4903.        {     rightcut := x+15-xmax }
  4904.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4905.        XOR AL,AL
  4906.  
  4907.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4908.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4909.        SHR AH,1    {rechtsschieben!}
  4910.        RCR AL,1
  4911.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4912.  
  4913.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  4914.        SHL DI,1
  4915.        MOV DI,CS:[OFFSET GADR + DI]
  4916.        MOV AX,x
  4917.        MOV BX,AX   {Kopie von x nach BX}
  4918.        SHR AX,1
  4919.        SHR AX,1
  4920.        ADD DI,AX
  4921.  
  4922.        MOV CX,rightcut
  4923.  
  4924.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4925.        {verwendet werden!}
  4926.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4927.        MOV BP,16+3
  4928.        SUB BP,CX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  4929.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  4930.  
  4931.  
  4932.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4933.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4934.  
  4935.        MOV DX,3C4h
  4936.        MOV AL,2
  4937.        AND BX,3
  4938.  
  4939.        JNE @mode0i {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  4940.        AND CX,3    {wir WriteMode1 verwenden!}
  4941.        JNE @mode0i
  4942.  
  4943.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  4944.        MOV AH,0Fh
  4945.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  4946.        MOV DX,3CEh
  4947.        MOV AX,4105h {WriteMode 1 waehlen}
  4948.        OUT DX,AX
  4949.        SUB BP,3     {BP auf die richtige Groesse bringen}
  4950.        JMP @lastPlane9  {abkuerzen}
  4951.        {---}
  4952.  
  4953.      @mode0i:
  4954.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  4955.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  4956.        PUSH AX     {und fuer spaeter merken}
  4957.  
  4958.        MOV DX,3CEh
  4959.        MOV AX,0004h    {Leseplane 0 waehlen}
  4960.        OUT DX,AX
  4961.  
  4962.        MOV BX,BP
  4963.        SHR BX,1
  4964.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  4965.  
  4966.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4967.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  4968.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4969.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  4970.  
  4971.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4972.        REP MOVSB   {1.Zeile}
  4973.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4974.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4975.        MOV CX,BX
  4976.        REP MOVSB   {2.Zeile}
  4977.        ADD DI,AX
  4978.        ADD SI,DX
  4979.        MOV CX,BX
  4980.        REP MOVSB   {3.Zeile}
  4981.        ADD DI,AX
  4982.        ADD SI,DX
  4983.        MOV CX,BX
  4984.        REP MOVSB   {4.Zeile}
  4985.        ADD DI,AX
  4986.        ADD SI,DX
  4987.        MOV CX,BX
  4988.        REP MOVSB   {5.Zeile}
  4989.        ADD DI,AX
  4990.        ADD SI,DX
  4991.        MOV CX,BX
  4992.        REP MOVSB   {6.Zeile}
  4993.        ADD DI,AX
  4994.        ADD SI,DX
  4995.        MOV CX,BX
  4996.        REP MOVSB   {7.Zeile}
  4997.        ADD DI,AX
  4998.        ADD SI,DX
  4999.        MOV CX,BX
  5000.        REP MOVSB   {8.Zeile}
  5001.        ADD DI,AX
  5002.        ADD SI,DX
  5003.        MOV CX,BX
  5004.        REP MOVSB   {9.Zeile}
  5005.        ADD DI,AX
  5006.        ADD SI,DX
  5007.        MOV CX,BX
  5008.        REP MOVSB   {10.Zeile}
  5009.        ADD DI,AX
  5010.        ADD SI,DX
  5011.        MOV CX,BX
  5012.        REP MOVSB   {11.Zeile}
  5013.        ADD DI,AX
  5014.        ADD SI,DX
  5015.        MOV CX,BX
  5016.        REP MOVSB   {12.Zeile}
  5017.        ADD DI,AX
  5018.        ADD SI,DX
  5019.        MOV CX,BX
  5020.        REP MOVSB   {13.Zeile}
  5021.        ADD DI,AX
  5022.        ADD SI,DX
  5023.        MOV CX,BX
  5024.        REP MOVSB   {14.Zeile}
  5025.        ADD DI,AX
  5026.        ADD SI,DX
  5027.        MOV CX,BX
  5028.        REP MOVSB   {15.Zeile}
  5029.        ADD DI,AX
  5030.        ADD SI,DX
  5031.        MOV CX,BX
  5032.        REP MOVSB   {16.Zeile}
  5033.        ADD DI,AX
  5034.        ADD SI,DX
  5035.  
  5036.  
  5037.        MOV DX,3CEh
  5038.        MOV AX,0104h  {Leseplane 1 waehlen}
  5039.        OUT DX,AX
  5040.  
  5041.        MOV DX,3C4h   {naechste Schreibplane:}
  5042.        POP AX
  5043.        SHL AH,1
  5044.        CMP AH,16
  5045.        JNE @nowrap1i
  5046.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5047.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5048.      @nowrap1i:
  5049.        OUT DX,AX
  5050.        PUSH AX
  5051.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5052.        SUB SI,16*4
  5053.  
  5054.  
  5055.        DEC BP        {BP:=16+2-rightcut}
  5056.        MOV BX,BP
  5057.        SHR BX,1
  5058.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  5059.  
  5060.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5061.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  5062.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5063.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  5064.  
  5065.        MOV CX,BX   {CX:=Bytes_je_Plane1_Zeile}
  5066.        REP MOVSB   {1.Zeile}
  5067.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5068.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5069.        MOV CX,BX
  5070.        REP MOVSB   {2.Zeile}
  5071.        ADD DI,AX
  5072.        ADD SI,DX
  5073.        MOV CX,BX
  5074.        REP MOVSB   {3.Zeile}
  5075.        ADD DI,AX
  5076.        ADD SI,DX
  5077.        MOV CX,BX
  5078.        REP MOVSB   {4.Zeile}
  5079.        ADD DI,AX
  5080.        ADD SI,DX
  5081.        MOV CX,BX
  5082.        REP MOVSB   {5.Zeile}
  5083.        ADD DI,AX
  5084.        ADD SI,DX
  5085.        MOV CX,BX
  5086.        REP MOVSB   {6.Zeile}
  5087.        ADD DI,AX
  5088.        ADD SI,DX
  5089.        MOV CX,BX
  5090.        REP MOVSB   {7.Zeile}
  5091.        ADD DI,AX
  5092.        ADD SI,DX
  5093.        MOV CX,BX
  5094.        REP MOVSB   {8.Zeile}
  5095.        ADD DI,AX
  5096.        ADD SI,DX
  5097.        MOV CX,BX
  5098.        REP MOVSB   {9.Zeile}
  5099.        ADD DI,AX
  5100.        ADD SI,DX
  5101.        MOV CX,BX
  5102.        REP MOVSB   {10.Zeile}
  5103.        ADD DI,AX
  5104.        ADD SI,DX
  5105.        MOV CX,BX
  5106.        REP MOVSB   {11.Zeile}
  5107.        ADD DI,AX
  5108.        ADD SI,DX
  5109.        MOV CX,BX
  5110.        REP MOVSB   {12.Zeile}
  5111.        ADD DI,AX
  5112.        ADD SI,DX
  5113.        MOV CX,BX
  5114.        REP MOVSB   {13.Zeile}
  5115.        ADD DI,AX
  5116.        ADD SI,DX
  5117.        MOV CX,BX
  5118.        REP MOVSB   {14.Zeile}
  5119.        ADD DI,AX
  5120.        ADD SI,DX
  5121.        MOV CX,BX
  5122.        REP MOVSB   {15.Zeile}
  5123.        ADD DI,AX
  5124.        ADD SI,DX
  5125.        MOV CX,BX
  5126.        REP MOVSB   {16.Zeile}
  5127.        ADD DI,AX
  5128.        ADD SI,DX
  5129.  
  5130.  
  5131.        MOV DX,3CEh
  5132.        MOV AX,0204h  {Leseplane 2 waehlen}
  5133.        OUT DX,AX
  5134.  
  5135.        MOV DX,3C4h   {naechste Schreibplane:}
  5136.        POP AX
  5137.        SHL AH,1
  5138.        CMP AH,16
  5139.        JNE @nowrap2i
  5140.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5141.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5142.      @nowrap2i:
  5143.        OUT DX,AX
  5144.        PUSH AX
  5145.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5146.        SUB SI,16*4
  5147.  
  5148.  
  5149.        DEC BP        {BP:=16+1-rightcut}
  5150.        MOV BX,BP
  5151.        SHR BX,1
  5152.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  5153.  
  5154.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5155.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  5156.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5157.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  5158.  
  5159.        MOV CX,BX   {CX:=Bytes_je_Plane2_Zeile}
  5160.        REP MOVSB   {1.Zeile}
  5161.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5162.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5163.        MOV CX,BX
  5164.        REP MOVSB   {2.Zeile}
  5165.        ADD DI,AX
  5166.        ADD SI,DX
  5167.        MOV CX,BX
  5168.        REP MOVSB   {3.Zeile}
  5169.        ADD DI,AX
  5170.        ADD SI,DX
  5171.        MOV CX,BX
  5172.        REP MOVSB   {4.Zeile}
  5173.        ADD DI,AX
  5174.        ADD SI,DX
  5175.        MOV CX,BX
  5176.        REP MOVSB   {5.Zeile}
  5177.        ADD DI,AX
  5178.        ADD SI,DX
  5179.        MOV CX,BX
  5180.        REP MOVSB   {6.Zeile}
  5181.        ADD DI,AX
  5182.        ADD SI,DX
  5183.        MOV CX,BX
  5184.        REP MOVSB   {7.Zeile}
  5185.        ADD DI,AX
  5186.        ADD SI,DX
  5187.        MOV CX,BX
  5188.        REP MOVSB   {8.Zeile}
  5189.        ADD DI,AX
  5190.        ADD SI,DX
  5191.        MOV CX,BX
  5192.        REP MOVSB   {9.Zeile}
  5193.        ADD DI,AX
  5194.        ADD SI,DX
  5195.        MOV CX,BX
  5196.        REP MOVSB   {10.Zeile}
  5197.        ADD DI,AX
  5198.        ADD SI,DX
  5199.        MOV CX,BX
  5200.        REP MOVSB   {11.Zeile}
  5201.        ADD DI,AX
  5202.        ADD SI,DX
  5203.        MOV CX,BX
  5204.        REP MOVSB   {12.Zeile}
  5205.        ADD DI,AX
  5206.        ADD SI,DX
  5207.        MOV CX,BX
  5208.        REP MOVSB   {13.Zeile}
  5209.        ADD DI,AX
  5210.        ADD SI,DX
  5211.        MOV CX,BX
  5212.        REP MOVSB   {14.Zeile}
  5213.        ADD DI,AX
  5214.        ADD SI,DX
  5215.        MOV CX,BX
  5216.        REP MOVSB   {15.Zeile}
  5217.        ADD DI,AX
  5218.        ADD SI,DX
  5219.        MOV CX,BX
  5220.        REP MOVSB   {16.Zeile}
  5221.        ADD DI,AX
  5222.        ADD SI,DX
  5223.  
  5224.  
  5225.        MOV DX,3CEh
  5226.        MOV AX,0304h  {Leseplane 3 waehlen}
  5227.        OUT DX,AX
  5228.  
  5229.        MOV DX,3C4h   {naechste Schreibplane:}
  5230.        POP AX
  5231.        SHL AH,1
  5232.        CMP AH,16
  5233.        JNE @nowrap3i
  5234.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5235.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5236.      @nowrap3i:
  5237.        OUT DX,AX
  5238.                      {Wert nicht mehr pushen!}
  5239.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5240.        SUB SI,16*4
  5241.  
  5242.  
  5243.  
  5244.        DEC BP        {BP:=16-rightcut}
  5245.      @lastplane9:
  5246.                      {BP direkt verwenden}
  5247.        SHR BP,1
  5248.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  5249.  
  5250.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5251.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  5252.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5253.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  5254.  
  5255.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  5256.        REP MOVSB   {1.Zeile}
  5257.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5258.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5259.        MOV CX,BP
  5260.        REP MOVSB   {2.Zeile}
  5261.        ADD DI,AX
  5262.        ADD SI,DX
  5263.        MOV CX,BP
  5264.        REP MOVSB   {3.Zeile}
  5265.        ADD DI,AX
  5266.        ADD SI,DX
  5267.        MOV CX,BP
  5268.        REP MOVSB   {4.Zeile}
  5269.        ADD DI,AX
  5270.        ADD SI,DX
  5271.        MOV CX,BP
  5272.        REP MOVSB   {5.Zeile}
  5273.        ADD DI,AX
  5274.        ADD SI,DX
  5275.        MOV CX,BP
  5276.        REP MOVSB   {6.Zeile}
  5277.        ADD DI,AX
  5278.        ADD SI,DX
  5279.        MOV CX,BP
  5280.        REP MOVSB   {7.Zeile}
  5281.        ADD DI,AX
  5282.        ADD SI,DX
  5283.        MOV CX,BP
  5284.        REP MOVSB   {8.Zeile}
  5285.        ADD DI,AX
  5286.        ADD SI,DX
  5287.        MOV CX,BP
  5288.        REP MOVSB   {9.Zeile}
  5289.        ADD DI,AX
  5290.        ADD SI,DX
  5291.        MOV CX,BP
  5292.        REP MOVSB   {10.Zeile}
  5293.        ADD DI,AX
  5294.        ADD SI,DX
  5295.        MOV CX,BP
  5296.        REP MOVSB   {11.Zeile}
  5297.        ADD DI,AX
  5298.        ADD SI,DX
  5299.        MOV CX,BP
  5300.        REP MOVSB   {12.Zeile}
  5301.        ADD DI,AX
  5302.        ADD SI,DX
  5303.        MOV CX,BP
  5304.        REP MOVSB   {13.Zeile}
  5305.        ADD DI,AX
  5306.        ADD SI,DX
  5307.        MOV CX,BP
  5308.        REP MOVSB   {14.Zeile}
  5309.        ADD DI,AX
  5310.        ADD SI,DX
  5311.        MOV CX,BP
  5312.        REP MOVSB   {15.Zeile}
  5313.        ADD DI,AX
  5314.        ADD SI,DX
  5315.        MOV CX,BP
  5316.        REP MOVSB   {16.Zeile}
  5317.  
  5318.        {--- falls Abkuerzung genommen wurde, muss WriteMode 0 wieder}
  5319.        {    gesetzt werden; hier der Einfachheit immer neugesetzt   }
  5320.        MOV AX,4005h
  5321.        MOV DX,3CEh
  5322.        OUT DX,AX
  5323.        {---}
  5324.  
  5325.        POP BP
  5326.        MOV AX,SEG @Data  {DS wiederherstellen}
  5327.        MOV DS,AX
  5328.  
  5329.     MOV AX,RandIndex
  5330.     ADD AX,XTiles
  5331.     MOV RandIndex,AX
  5332.     MOV AX,yt
  5333.     INC AX
  5334.     MOV yt,AX
  5335.     MOV DX,y
  5336.     ADD DX,16
  5337.     MOV y,DX
  5338.     CMP DX,YMAX+1-16
  5339.     JBE @repeat5
  5340.   @ende:
  5341.  
  5342.  
  5343.   {------- ab hier: Sprites auf aktuelle Grafikseite bringen}
  5344.   @Sprites_zeichnen:
  5345.     MOV SI,NMAX*2
  5346.     PUSH BP      {BP nachher wieder poppen!}
  5347.  
  5348.     @zeichne:
  5349.  
  5350.     {DS = normales Datensegment, ES = Grafikseitensegment, }
  5351.     {SI = Spritepositionsnummer*2                          }
  5352.     @SZeich:
  5353.       MOV BX,[SI + OFFSET SpriteN]   {BX=SpriteN[?]=Spriteladenummer}
  5354.       SHL BX,1                       {BX = Spriteladenummer*2}
  5355.  
  5356.     {Jetzt: "SpriteN[?]:=SpriteN[NextSprite[?]]" berechnen:}
  5357.       MOV BX,[BX + OFFSET NextSprite] {AX=NextSprite[SpriteN[?]]}
  5358.       MOV [SI + OFFSET SpriteN],BX    {als neue SpriteN[?] uebernehmen}
  5359.       SHL BX,1
  5360.  
  5361.  
  5362.       JNZ @aktiv
  5363.       JMP @noSprite
  5364.  
  5365.  
  5366.     @aktiv:
  5367.       PUSH SI           {Spritepositionsnummer*2 retten}
  5368.  
  5369.       MOV DX,[SI + OFFSET SpriteX]   {if SpriteX>xmax then skip_sprite }
  5370.       SUB DX,StartVirtualX           {virtuelle -> absolute Koordinaten}
  5371.       CMP DX,XMAX
  5372.       JLE @L0
  5373.     @ToSprite_fertig:                {Sprungleiste zu @Sprite_fertig}
  5374.       JMP @Sprite_fertig
  5375.     @L0:
  5376.       MOV CS:WORD PTR @akt_SpriteX+1,DX
  5377.       MOV DI,[SI + OFFSET SpriteY]   {DI = SpriteY_virtuell}
  5378.       SUB DI,StartVirtualY           {DI = SpriteY (absolut!)}
  5379.       MOV DS,[BX + OFFSET SPRITEAD]  {!!!DS = ^Spritedaten !!!}
  5380.       MOV AX,[Breite]                {AX = Breite in 4er-Gruppen}
  5381.       MOV CS:WORD PTR @max_Breite+1,AX
  5382.       MOV SI,AX                      {SI = dto.}
  5383.       SHL AX,1
  5384.       SHL AX,1                       {AX = max_Breite_in_Punkten}
  5385.       ADD AX,DX                      {AX = max_Breite_in_Punkten+SpriteX}
  5386.       JS @ToSprite_fertig
  5387.       MOV BX,DI                      {if SpriteY>=0 then starty:=+SpriteY}
  5388.       NEG DI                         {              else starty:=-SpriteY}
  5389.       MOV BP,DI
  5390.       JG @Top_cut
  5391.       XOR DI,DI
  5392.     @Top_cut:                        {DI = starty, BP = -SpriteY}
  5393.       MOV AX,[Hoehe]                 {AX = Hoehe (in Zeilen)  }
  5394.       CMP DI,AX                      {if starty>=Hoehe then skip_sprite}
  5395.       JGE @ToSprite_fertig
  5396.       ADD BP,YMAX                    {BP = -SpriteY+ymax}
  5397.       JL @ToSprite_fertig            {(etwas frei:) }
  5398.       CMP AX,BP                      {if Hoehe+SpriteY>ymax   }
  5399.       JG @To_then                    { then [ endy:=199-SpriteY }
  5400.       DEC AX                         {       if endy<0 then skip_sprite ] }
  5401.       MOV BP,AX                      { else endy:=Hoehe-1 }
  5402.  
  5403.     {BP = endy, SI=[@max_Breite+1] = max_Breite_in_4er_Gruppen, }
  5404.     {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX,  }
  5405.     {DS = ^Spritedaten, ES = ^Grafikseite}
  5406.     @To_then:
  5407.       MOV AX,BP
  5408.       SUB BP,DI
  5409.  
  5410.       SHL BP,1
  5411.       MOV [End_min_Start],BP         {= (endy-starty)*2 =Yaktuell*2}
  5412.       ADD BX,AX
  5413.       SHL BX,1
  5414.       MOV BX,CS:[OFFSET gadr + BX]   {BX=zeilenadr:=(endy+SpriteY)*LINESIZE}
  5415.       MOV [zeilenadr],BX             {auch nach [zeilenadr] }
  5416.       MOV BP,DX
  5417.       MUL SI                         {AX = endy*max_breite_in_4er =yoffset}
  5418.       MOV [yoffset_],AX              {auch nach [yoffset_]}
  5419.       SHL DI,1                       {DI = starty*2}
  5420.       MOV CS:WORD PTR @Starty_2+1,DI {auch nach [@Starty_2+1] }
  5421.  
  5422.       {kleiner Einschub: anhand des Modusbytes des Sprites entscheiden, ob}
  5423.       {eine andere Routine zur Darstellung des Sprites als die gerade ak- }
  5424.       {tive benoetigt wird und wenn ja, diese in Position bringen!        }
  5425.       {Verwendete Register: AX und SI                                     }
  5426.        MOV AL,[Modus]                {Modusbyte des Sprites holen}
  5427.        XOR AH,AH
  5428.        SHL AX,1
  5429.        MOV SI,AX
  5430.        MOV SI,CS:[OFFSET Adressen +SI] {Pointer auf zugehoerige Routine holen}
  5431.        MOV AX,CS:[SI]
  5432.        CMP AX,CS:[WORD PTR @Patch1]    {ist diese Routine bereits aktiv?}
  5433.        JE @no_newcode                  {ja, nix zu tun}
  5434.        PUSH DS                         {nein, kopiere die Routine an die}
  5435.        PUSH CS                         {entsprechenden Stellen}
  5436.        POP DS
  5437.        MOV [WORD PTR @Patch1],AX
  5438.        MOV [WORD PTR @Patch2],AX
  5439.        MOV [WORD PTR @Patch3],AX
  5440.        MOV [WORD PTR @Patch4],AX
  5441.        INC SI
  5442.        INC SI
  5443.        LODSW
  5444.        MOV [WORD PTR @Patch1+2],AX
  5445.        MOV [WORD PTR @Patch2+2],AX
  5446.        MOV [WORD PTR @Patch3+2],AX
  5447.        MOV [WORD PTR @Patch4+2],AX
  5448.        LODSW
  5449.        MOV [WORD PTR @Patch1+4],AX
  5450.        MOV [WORD PTR @Patch2+4],AX
  5451.        MOV [WORD PTR @Patch3+4],AX
  5452.        MOV [WORD PTR @Patch4+4],AX
  5453.        LODSW
  5454.        MOV [WORD PTR @Patch1+6],AX
  5455.        MOV [WORD PTR @Patch2+6],AX
  5456.        MOV [WORD PTR @Patch3+6],AX
  5457.        MOV [WORD PTR @Patch4+6],AX
  5458.        LODSW
  5459.        MOV [WORD PTR @Patch1+8],AX
  5460.        MOV [WORD PTR @Patch2+8],AX
  5461.        MOV [WORD PTR @Patch3+8],AX
  5462.        MOV [WORD PTR @Patch4+8],AX
  5463.        LODSW
  5464.        MOV [WORD PTR @Patch1+10],AX
  5465.        MOV [WORD PTR @Patch2+10],AX
  5466.        MOV [WORD PTR @Patch3+10],AX
  5467.        MOV [WORD PTR @Patch4+10],AX
  5468.        LODSW
  5469.        MOV [WORD PTR @Patch1+12],AX
  5470.        MOV [WORD PTR @Patch2+12],AX
  5471.        MOV [WORD PTR @Patch3+12],AX
  5472.        MOV [WORD PTR @Patch4+12],AX
  5473.        LODSW
  5474.        MOV [WORD PTR @Patch1+14],AX
  5475.        MOV [WORD PTR @Patch2+14],AX
  5476.        MOV [WORD PTR @Patch3+14],AX
  5477.        MOV [WORD PTR @Patch4+14],AX
  5478.  
  5479.        POP DS                          {DS wiederherstellen}
  5480.      @no_newcode:
  5481.  
  5482.  
  5483.     {(AX=)[yoffset_]     = yoffset }
  5484.     { BX=[zeilenadr]     = (endy+SpriteY)*LINESIZE}
  5485.     { DI=[@Starty_2+1]   = starty*2}
  5486.     {(SI=[@max_Breite+1] = max_Breite_in_4er_) }
  5487.     { BP                 = SpriteX}
  5488.     { DS                 = ^Spritedaten}
  5489.     { ES                 = ^Grafikseite}
  5490.     { [end_min_start]    = (endy-starty)*2 =Yaktuell*2}
  5491.     { [@max_Breite+1]    = max_Breite_in_4er_Gruppen  }
  5492.     { [@akt_SpriteX+1]   = SpriteX}
  5493.     @eine_Zeile:
  5494.       MOV SI,[end_min_start]         {SI = Yaktuell*2 }
  5495.       ADD SI,DI                      {startx:=sprite[WORD PTR sprite[L]+  }
  5496.       MOV DI,SI                      {               (Yaktuell+starty)*2] }
  5497.       ADD SI,[Left]
  5498.       MOV SI,[SI]                    {SI = startx, DI = (Yaktuell+starty)*2}
  5499.       MOV AX,BP                      
  5500.       ADD AX,SI                      {AX=bildschirmstartx:=SpriteX+startx   }
  5501.       CMP AX,XMAX                    {if bildschirmstartx>xmax then skip_zeile}
  5502.       JG @ToZeile_fertig
  5503.       MOV CX,SI                      {CX=startx}
  5504.       OR AX,AX                       {licutoff_in_Punkten:=startx}
  5505.       JGE @L1                        {if bildschirmstartx<0 then }
  5506.       SUB SI,AX                      { [dec(startx,bildschirmstartx) }
  5507.       XOR AX,AX                      {  bildschirmstartx:=0          }
  5508.       MOV CX,BP                      {  licutoff_in_Punkten:=-SpriteX] }
  5509.       NEG CX
  5510.     @L1:                             {CX=[licutoff_]= licutoff_in_Punkten, }
  5511.       MOV [licutoff_],CX             {SI = startx, AX = bildschirmstartx   }
  5512.       ADD DI,[Right]
  5513.       MOV DI,[DI]                    {DI=endx:=sprite[WORD PTR sprite[R]+  }
  5514.                                      {                (Yaktuell+starty)*2] }
  5515.       MOV DX,BP                      
  5516.       NEG DX                         {DX = -SpriteX }
  5517.       MOV BP,DI
  5518.       SUB BP,SI                      {BP = endx-startx }
  5519.       SUB DX,DI
  5520.       ADD DX,XMAX                    {DX=ueberhang:=xmax-(SpriteX+endx) }
  5521.       JNS @kein_Ueberhang_rechts
  5522.       ADD BP,DX
  5523.     @kein_Ueberhang_rechts:          {BP = sichtbare Breite dieser Zeile -1}
  5524.       OR BP,BP
  5525.       JNS @L6
  5526.     @ToZeile_fertig:
  5527.       JMP @Zeile_fertig              {if Breite<=0 then skip_zeile }
  5528.     @L6:
  5529.       ADD BP,4
  5530.  
  5531.       { AX               = bildschirmstartx}
  5532.       { BX=[zeilenadr]   = (endy+SpriteY)*LINESIZE }
  5533.       { CX=[licutoff_]   = licutoff_in_Punkten}
  5534.       {(DX               = (negativer) ueberhang (falls Wert<0) ) }
  5535.       {(SI               = startx) }
  5536.       {(DI               = endx) }
  5537.       { BP               = Breite fuer diese Zeile in Punkten +3 }
  5538.       { DS               = ^Spritedaten}
  5539.       { ES               = ^Grafikseite}
  5540.       { [@max_Breite+1]  = max_Breite_in_4er_) }
  5541.       { [end_min_start]  = (endy-starty)*2 =Yaktuell*2}
  5542.       { [@Starty_2+1]    = starty*2}
  5543.       { [@max_Breite+1]  = max_Breite_in_4er_Gruppen, }
  5544.       { [@akt_SpriteX+1] = SpriteX}
  5545.       MOV [bildx],AX                 {bildschirmstartx retten}
  5546.       MOV DX,CX                      {DX = licutoff_in_Punkten}
  5547.       MOV CX,BP
  5548.       SHR CX,1
  5549.       SHR CX,1                       {CX = Breite DIV 4}
  5550.       JCXZ @Plane1
  5551.  
  5552.       {SI=Quellzeiger:=sprite[WORD PTR (licutoff_in_Punkten+0 AND 3)*2 }
  5553.       {                       +(licutoff_in_Punkten+0) DIV 4 +yoffset  }
  5554.       MOV SI,DX
  5555.       AND SI,3                       
  5556.       SHL SI,1                       {SI = ((licutoff_in_Punkten+0) AND 3)*2}
  5557.       MOV SI,[SI]                    
  5558.       MOV DI,DX
  5559.       SHR DI,1
  5560.       SHR DI,1
  5561.       ADD SI,DI
  5562.       ADD SI,[yoffset_]              {SI = sprite[WORD PTR (licutoff_...)] }
  5563.                                      {     +(licutoff_in_Punkten+i) DIV 4  }
  5564.                                      {     +yoffset                        }
  5565.  
  5566.       {DI=Zielzeiger:=(bildschirmstartx+0) DIV 4 +zeilenadr}
  5567.       MOV DI,AX                      {DI = bildschirmstartx }
  5568.       SHR DI,1
  5569.       SHR DI,1
  5570.       ADD DI,BX
  5571.       MOV BL,AL
  5572.       AND BX,3                       {BX = (bildschirmstartx+i) AND 3 }
  5573.       MOV AH,Translate[BX]           {AH = 1,2,4,8 fuer BX=0,1,2,3    }
  5574.       MOV AL,2
  5575.       MOV DX,3C4h
  5576.       OUT DX,AX                      {Plane auswaehlen}
  5577.  
  5578.       XCHG BX,DI
  5579.       {CX Bytes von DS:SI nach ES:BX uebertragen }
  5580.       {Hierher kommt die Routine zur Datenuebertragung!}
  5581.     @Patch1:
  5582.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5583.  
  5584.     @Plane1:
  5585.       MOV DX,[bildx]
  5586.       INC DX                         {DX = bildschirmstartx+1}
  5587.       MOV BX,DX
  5588.       SHR BX,1
  5589.       SHR BX,1                       {BX=zielzeiger:=(bildschirmstartx+1) }
  5590.       ADD BX,[zeilenadr]             {                DIV 4 +zeilenadr    }
  5591.       MOV CX,BP
  5592.       DEC CX                         {CX = Breite dieser Zeile +3 -1 }
  5593.       SHR CX,1
  5594.       SHR CX,1                       {CX = Bytes_zu_moven fuer i=1 }
  5595.       JCXZ @Plane2
  5596.       MOV DI,[licutoff_]
  5597.       INC DI                         {DI = (licutoff_in_Punkten+1) }
  5598.       MOV SI,DI
  5599.       AND SI,3
  5600.       SHL SI,1                       {SI = ((licutoff_in_Punkten+1) AND 3)*2}
  5601.       MOV SI,[SI]                    {SI = sprite[WORD PTR licutoff_...]  }
  5602.       SHR DI,1                       {     +(licutoff_in_Punkten+1) DIV 4 }
  5603.       SHR DI,1                       {     +yoffset                       }
  5604.       ADD SI,DI
  5605.       ADD SI,[yoffset_]              {SI = Quellzeiger, }
  5606.                                      {DI = (licutoff_in_Punkten+1) DIV 4 }
  5607.  
  5608.       MOV DI,DX                      {DI = bildschirmstartx+1}
  5609.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  5610.       MOV AH,Translate[DI]           {Maske fuer Portzugriff laden}
  5611.       MOV AL,2
  5612.       MOV DX,3C4h                    {Plane anwaehlen}
  5613.       OUT DX,AX
  5614.  
  5615.       {Hierher kommt die Routine zur Datenuebertragung!}
  5616.     @Patch2:
  5617.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5618.  
  5619.     @Plane2:
  5620.       MOV DX,[bildx]
  5621.       ADD DX,2
  5622.       MOV BX,DX
  5623.       SHR BX,1
  5624.       SHR BX,1
  5625.       ADD BX,[zeilenadr]
  5626.       MOV CX,BP
  5627.       SUB CX,2
  5628.       SHR CX,1
  5629.       SHR CX,1
  5630.       JCXZ @Plane3
  5631.       MOV DI,[licutoff_]
  5632.       ADD DI,2
  5633.       MOV SI,DI
  5634.       AND SI,3
  5635.       SHL SI,1
  5636.       MOV SI,[SI]
  5637.       SHR DI,1
  5638.       SHR DI,1
  5639.       ADD SI,DI
  5640.       ADD SI,[yoffset_]
  5641.  
  5642.       MOV DI,DX                      {DI = bildschirmstartx+2}
  5643.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  5644.       MOV AH,Translate[DI]
  5645.       MOV AL,2
  5646.       MOV DX,3C4h
  5647.       OUT DX,AX
  5648.  
  5649.       {Hierher kommt die Routine zur Datenuebertragung!}
  5650.     @Patch3:
  5651.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5652.  
  5653.     @Plane3:
  5654.       MOV DX,[bildx]
  5655.       ADD DX,3
  5656.       MOV BX,DX
  5657.       SHR BX,1
  5658.       SHR BX,1
  5659.       ADD BX,[zeilenadr]
  5660.       MOV CX,BP
  5661.       SUB CX,3
  5662.       SHR CX,1
  5663.       SHR CX,1
  5664.       JCXZ @Zeile_fertig
  5665.       MOV DI,[licutoff_]
  5666.       ADD DI,3
  5667.       MOV SI,DI
  5668.       AND SI,3
  5669.       SHL SI,1
  5670.       MOV SI,[SI]
  5671.       SHR DI,1
  5672.       SHR DI,1
  5673.       ADD SI,DI
  5674.       ADD SI,[yoffset_]
  5675.  
  5676.       MOV DI,DX                      {DI = bildschirmstartx+3}
  5677.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  5678.       MOV AH,Translate[DI]
  5679.       MOV AL,2
  5680.       MOV DX,3C4h
  5681.       OUT DX,AX
  5682.  
  5683.       {Hierher kommt die Routine zur Datenuebertragung!}
  5684.     @Patch4:
  5685.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5686.  
  5687.     @Zeile_fertig:
  5688.       MOV AX,[yoffset_]
  5689.     @max_Breite:
  5690.       SUB AX,1234
  5691.       MOV [yoffset_],AX
  5692.       MOV BX,[zeilenadr]
  5693.       SUB BX,LINESIZE
  5694.       MOV [zeilenadr],BX
  5695.       SUB WORD PTR [end_min_start],2
  5696.       JS @Sprite_fertig
  5697.  
  5698.     @Starty_2:
  5699.       MOV DI,1234
  5700.     @akt_SpriteX:
  5701.       MOV BP,1234
  5702.       JMP @eine_Zeile
  5703.  
  5704.     @Sprite_fertig:
  5705.       POP SI
  5706.       MOV AX,SEG @Data
  5707.       MOV DS,AX
  5708.  
  5709.     @noSprite:
  5710.       DEC SI
  5711.       DEC SI
  5712.       JS @fertig
  5713.       JMP @zeichne
  5714.     @fertig:
  5715.  
  5716.       POP BP
  5717.  
  5718.     {Die Grafikseite ist nun fertiggestellt und muss noch angezeigt werden:}
  5719.       cli
  5720.       mov  dx,3DAh
  5721.     @WaitNotVSyncLoop:
  5722.       in   al,dx
  5723.       and  al,8
  5724.       jnz  @WaitNotVSyncLoop
  5725.     @WaitVSyncLoop:
  5726.       in   al,dx
  5727.       and  al,8
  5728.       jz   @WaitVSyncLoop
  5729.  
  5730.       MOV DX,$3D4                {CRT-Controller}
  5731.       MOV AL,$0D                 {LB-Startadress-Register}
  5732.       OUT DX,AL
  5733.       INC DX
  5734.                                  { Realisiere "AX:=Offset_Adr[Page]": }
  5735.       MOV SI,PAGE                {Page-Wert *2 (da Worteintraege!)}
  5736.       MOV BX,SI                  {Page-Wert in BX merken!}
  5737.       SHL SI,1                   {dazu Startadresse des Feldes addieren}
  5738.       ADD SI,OFFSET Offset_Adr-StartIndex*2  {evtl. Verschiebung korrigieren}
  5739.       LODSW                      {und Wert holen}
  5740.       OUT DX,AL                  {LB der neuen Startadresse setzen}
  5741.       DEC DX
  5742.       MOV AL,$0C
  5743.       OUT DX,AL
  5744.       INC DX
  5745.       MOV AL,AH                  {HB der neuen Startadresse setzen}
  5746.       OUT DX,AL
  5747.       STI
  5748.  
  5749.       NEG BX       {neuer PAGE-Wert := 1-alter PAGE-Wert, d.h.:  }
  5750.       ADD BX,1     {IF PAGE=0 THEN PAGE:=1 ELSE (PAGE=1) PAGE:=0 }
  5751.       MOV PAGE,BX
  5752.  
  5753.       SHL BX,1     {neuer PAGEADR-Wert := Segment_Adr[PAGE] }
  5754.       ADD BX,OFFSET Segment_Adr-StartIndex*2
  5755.       MOV AX,[BX]
  5756.       MOV PAGEADR,AX
  5757.  
  5758.       {Jetzt ueberpruefen, ob gesetzte Zyklus(mindest)zeit abgelaufen ist:}
  5759.     @L10:
  5760.       MOV AL,TimeFlag   {Bit 7 = 0/1 fuer Zeit ist abgelaufen/laeuft noch }
  5761.       AND AL,$80
  5762.       JE @L10
  5763.  
  5764.       {Zeitueberwachung fuer naechsten Zyklus starten:}
  5765.       MOV AL,IsAT                 {ist das ein AT/386? ($0/$80=ja/nein)}
  5766.       OR AL,AL                    {Zeitmechanismus geht nur auf AT/386 }
  5767.       JNE @L11                    {anderenfalls keine Zeitueberwachung!}
  5768.       MOV TimeFlag,AL             {AL=0 zugleich als Init-Wert benutzen}
  5769.       MOV DX,WORD PTR CycleTime   {Mindestzykluszeit (in Mikrosekunden)}
  5770.       MOV CX,WORD PTR CycleTime+2 {eintragen: CX=HIGH-Word, DX=LOW-Word}
  5771.       MOV BX,OFFSET TimeFlag      {ES:BX=Zeiger auf TimeFlag, Bit 7=0/1}
  5772.       MOV AX,DS                   {fuer: Zeit laeuft noch/ist um       }
  5773.       MOV ES,AX
  5774.       MOV AX,8300h                {Zeitueberwachung starten}
  5775.       INT 15h
  5776.     @L11:
  5777.  END
  5778. END;
  5779.  
  5780.  
  5781. FUNCTION LoadSprite(name:String; number:WORD):WORD;
  5782. { in: name   = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
  5783. {     number = Nummer, die das erste Sprite aus diesem File bekommen soll }
  5784. {out: Anzahl der aus dem File gelesenen Sprites (0 = Fehler trat auf)     }
  5785. {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
  5786. {     zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt    }
  5787. {     alle Spritedaten auf den Heap, und zwar derart, dass die Adresse    }
  5788. {     immer auf eine Segmentgrenze fällt. Diese Anfangsadressen werden    }
  5789. {     dann in der Tabelle SPRITEAD[number] abgelegt; sind mehrere Sprites }
  5790. {     in der Datei so werden sie mit fortlaufender Nummer eingetragen,    }
  5791. {     also number+i }
  5792. LABEL quit_loop;
  5793. VAR p1,p2:Pointer;
  5794.     len:LONGINT;
  5795.     f:File;
  5796.     count,Kopf:WORD;
  5797.     Header:SpriteHeader;
  5798. BEGIN
  5799.  count:=0;  {Zahl der bisher eingelesenen Sprites}
  5800.  Kopf:=SizeOf(SpriteHeader);
  5801.  assign(f,name);
  5802.  {$I-} reset(f,1); {$I+}
  5803.  if (ioresult<>0)
  5804.   THEN BEGIN  {Datei existiert nicht oder nicht unter diesem Pfad}
  5805.         Error:=Err_FileIO;
  5806.         loadSprite:=0; exit
  5807.        END;
  5808.  len:=filesize(f);  {Dateilaenge ermitteln}
  5809.  if (maxavail<len+16)
  5810.   THEN BEGIN
  5811.         Error:=Err_NotEnoughMemory;
  5812.         goto quit_loop;
  5813.        END;
  5814.  if (number=0) or (number>LoadMAX)
  5815.   THEN BEGIN
  5816.         Error:=Err_InvalidSpritenumber;
  5817.         goto quit_loop;
  5818.        END;
  5819.  WHILE NOT EOF(f) DO
  5820.  BEGIN
  5821.   {Zunaechst den Spriteheader einlesen: }
  5822.   {$I-}     {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
  5823.   blockread(f,Header,Kopf);
  5824.   {$I+}
  5825.  
  5826.   IF (ioresult<>0)
  5827.    THEN BEGIN
  5828.          Error:=Err_FileIO;
  5829.          goto quit_loop;
  5830.         END;
  5831.   IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
  5832.    THEN BEGIN
  5833.          Error:=Err_NoSprite;
  5834.          goto quit_loop;
  5835.         END;
  5836.   IF (Header.SpriteLength>MaxAvail+15)    {noch genug Platz da?}
  5837.    THEN BEGIN
  5838.          Error:=Err_NotEnoughMemory;
  5839.          goto quit_loop;
  5840.         END;
  5841.  
  5842.   {Jetzt eigentliche Spritedaten einlesen: }
  5843.   getmem(p1,Header.SpriteLength+15);       {genug Platz reservieren}
  5844.   IF (LONGINT(p1) mod 16)=0
  5845.    THEN p2:=p1                             {p2 auf Segmentgrenze bringen}
  5846.    ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
  5847.  
  5848.   MOVE(Header,p2^,Kopf);  {Spriteheader auf Heap bringen}
  5849.   LONGINT(p1):=LONGINT(p2)+Kopf;   {zeigt genau hinter den Header}
  5850.  
  5851.   {$I-}     {jetzt den "Rest" des Sprites laden}
  5852.   blockread(f,p1^,Header.SpriteLength-Kopf);
  5853.   {$I+}
  5854.   IF (ioresult<>0)
  5855.    THEN BEGIN
  5856.          Error:=Err_FileIO;
  5857.          goto quit_loop;
  5858.         END;
  5859.  
  5860.   {der Spritenummer zuordnen:}
  5861.   spritead[number+count]:=(longint(p2) shr 16)
  5862.                          +(longint(p2) and 65535) shr 4;
  5863.   INC(count);
  5864.  END;
  5865.  
  5866. quit_loop: ;
  5867.  close(f);
  5868.  loadSprite:=count
  5869. END;
  5870.  
  5871. FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
  5872. { in: name   = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
  5873. {     number = 0..255 = Tilenummer fuer das erste Sprite der Datei        }
  5874. {out: Anzahl der aus dem File gelesenen Tiles (0 = Fehler trat auf)       }
  5875. {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
  5876. {     zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt    }
  5877. {     alle Sprites, zerlegt diese in Tiles und legt sie in der 4.Grafik-  }
  5878. {     seite ab, beginnend mit der uebergebenen Nummer number              }
  5879. {     Da eine Kachel 16x16 Punkte gross ist, muessen die Sprites ein Viel-}
  5880. {     faches von 16 Punkten in x- und y-Richtung sein                     }
  5881. {     Enthaelt die Datei mehrere Tiles, so werden sie zeilenweise geladen,}
  5882. {     jede Zeile dabei in der Reihenfolge von links nach rechts           }
  5883. LABEL quit_loop;
  5884. TYPE split=RECORD loword,hiword:WORD END;
  5885. VAR p1:Pointer;
  5886.     len,ad,p:LONGINT;
  5887.     f:File;
  5888.     count,Kopf,ZielOfs,step,yoffset:WORD;
  5889.     pSeg,pOfs:ARRAY[0..3] OF WORD;
  5890.     Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
  5891.     Header:SpriteHeader;
  5892. BEGIN
  5893.  count:=0;  {Zahl der bisher eingelesenen Sprites}
  5894.  Kopf:=SizeOf(SpriteHeader);
  5895.  assign(f,name);
  5896.  {$I-} reset(f,1); {$I+}
  5897.  if (ioresult<>0)
  5898.   THEN BEGIN  {Datei existiert nicht oder nicht unter diesem Pfad}
  5899.         Error:=Err_FileIO;
  5900.         LoadTile:=0; exit
  5901.        END;
  5902.  len:=filesize(f);  {Dateilaenge ermitteln}
  5903.  if (maxavail<len+16)
  5904.   THEN BEGIN
  5905.         Error:=Err_NotEnoughMemory;
  5906.         goto quit_loop;
  5907.        END;
  5908.  WHILE NOT EOF(f) DO
  5909.  BEGIN
  5910.   {Zunaechst den Spriteheader einlesen: }
  5911.   {$I-}     {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
  5912.   blockread(f,Header,Kopf);
  5913.   {$I+}
  5914.  
  5915.   IF (ioresult<>0)
  5916.    THEN BEGIN
  5917.          Error:=Err_FileIO;
  5918.          goto quit_loop;
  5919.         END;
  5920.   IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
  5921.    THEN BEGIN
  5922.          Error:=Err_NoTile;  {oder Err_NoSprite!}
  5923.          goto quit_loop
  5924.         END;
  5925.   IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
  5926.      (Header.Hoehe_in_Zeilen MOD 16<>0)   {Groesse Vielfaches von 16?}
  5927.    THEN BEGIN
  5928.          Error:=Err_NoTile;
  5929.          goto quit_loop
  5930.         END
  5931.    ELSE BEGIN {ja, Anzahl Tiles in diesem Spritefile ermitteln}
  5932.          Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
  5933.          Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
  5934.          step:=Breite_in_Tiles*4; {Schrittweite beim laden}
  5935.         END;
  5936.   IF (Header.SpriteLength>MaxAvail)    {noch genug Platz da?}
  5937.    THEN BEGIN
  5938.          Error:=Err_NotEnoughMemory;
  5939.          goto quit_loop;
  5940.         END;
  5941.  
  5942.   {Jetzt eigentliche Spritedaten einlesen: }
  5943.   getmem(p1,Header.SpriteLength);      {genug Platz reservieren}
  5944.  
  5945.   {$I-}     {jetzt den "Rest" des Sprites laden}
  5946.   blockread(f,p1^,Header.SpriteLength-Kopf);
  5947.   {$I+}
  5948.   IF (ioresult<>0)
  5949.    THEN BEGIN
  5950.          Error:=Err_FileIO;
  5951.          goto quit_loop;
  5952.         END;
  5953.  
  5954.   ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
  5955.   FOR i:=0 TO 3 DO
  5956.    BEGIN
  5957.     p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
  5958.    END;
  5959.  
  5960.   FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
  5961.    BEGIN
  5962.     yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
  5963.     FOR x:=0 TO Pred(Breite_in_Tiles) DO
  5964.      BEGIN
  5965.       IF count+number>255
  5966.        THEN BEGIN
  5967.              Error:=Err_InvalidTileNumber;
  5968.              goto quit_loop
  5969.             END;
  5970.       ZielOfs:=(number+count) SHL 6;
  5971.       FOR i:=0 TO 3 DO
  5972.        BEGIN
  5973.         PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
  5974.         FOR zeilen:=0 TO 15 DO
  5975.          BEGIN
  5976.           move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
  5977.                mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
  5978.                16 DIV 4);
  5979.          END;
  5980.        END;
  5981.  
  5982.       INC(count);
  5983.      END;
  5984.    END;
  5985.   Dispose(p1);
  5986.  END;
  5987.  
  5988. quit_loop: ;
  5989.  close(f);
  5990.  LoadTile:=count
  5991. END;
  5992.  
  5993. PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
  5994. { in: (x1,y1) = linke obere Ecke des Bereiches (virtuelle Koord.)}
  5995. {     (x2,y2) = dto., rechte untere Ecke}
  5996. {out: (BackX1,BackY1), (BackX2,BackY2) = auf 16er Raster gerundete Koord.  }
  5997. {     XTiles, YTiles = Breite und Hoehe des gewaehlten Bereiches in Kacheln}
  5998. {rem: Die li. obere Ecke wird nach links oben gezogen, die re. untere nach }
  5999. {     rechts unten!}
  6000. {     Die Anwendung dieser Routine ist natuerlich nur fuer den Hintergrund-}
  6001. {     modus SCROLLING sinnvoll}
  6002. BEGIN
  6003.  BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
  6004.  BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
  6005.  xtiles:=succ(BackX2-BackX1) shr 4;
  6006.  ytiles:=succ(BackY2-BackY1) shr 4;
  6007.  IF (xtiles OR ytiles)<=0
  6008.   THEN Error:=Err_InvalidCoordinates
  6009.  ELSE IF xtiles*ytiles>MaxTiles
  6010.   THEN Error:=Err_BackgroundToBig;
  6011. END;
  6012.  
  6013. PROCEDURE SetBackgroundMode(mode:BYTE);
  6014. { in: mode = gewuenschter Hintergrundmodus STATIC oder SCROLLING}
  6015. {out: Backgroundmode = gesetzter Modus STATIC/SCROLLING}
  6016. BEGIN
  6017.  IF (mode<>STATIC) AND (mode<>SCROLLING)
  6018.   THEN Error:=Err_InvalidMode
  6019.   ELSE Backgroundmode:=mode
  6020. END;
  6021.  
  6022. PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
  6023. { in: x,y   = virtuelle Koordinate, an die die Kachel plaziert werden soll}
  6024. {out: TileNr= Nummer der zu plazierenden Kachel}
  6025. {rem: Der Punkt (x,y) wird zunaechst auf 16er Raster gebracht!  }
  6026. {     Die Anwendung dieser Routine ist nur fuer den Hintergrund-}
  6027. {     modus SCROLLING sinnvoll}
  6028. VAR index:WORD;
  6029. BEGIN
  6030.  ASM
  6031.     MOV AX,x        {berechne relativen X-Abstand vom linken Rand des}
  6032.     SUB AX,BackX1   {definierten Bereiches in "x" mittels der Formel:}
  6033.     SAR AX,1        { x:=((x AND $FFF0)-BackX1) DIV 16 (nicht SHR 4)!}
  6034.     SAR AX,1        {"AND $FFF0" kann dabei entfallen, da in BackX1  }
  6035.     SAR AX,1        {die letzte Hex-Ziffer $0 ist!                   }
  6036.     SAR AX,1
  6037.     MOV x,AX
  6038.  
  6039.     MOV AX,y        {dto. fuer Abstand der y-Koordinate vom oberen   }
  6040.     SUB AX,BackY1   {Rand: y:=((y AND $FFF0)-BackY1) DIV 16          }
  6041.     SAR AX,1
  6042.     SAR AX,1
  6043.     SAR AX,1
  6044.     SAR AX,1
  6045.     MOV y,AX
  6046.  END;
  6047.  
  6048.  IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
  6049.   THEN Error:=Err_InvalidCoordinates
  6050.   ELSE BEGIN {jede Kachelzeile ist XTiles breit, jede Kachel 16x16 Punkte}
  6051.         index:=y*XTiles+x;  {eigentlich: (x MOD XTiles)}
  6052.         BackTile[index]:=TileNr;
  6053.        END;
  6054. END;
  6055.  
  6056.  
  6057. PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
  6058. { in: Sp = SpriteLADEnummer, dessen Modusbyte veraendert werden soll}
  6059. {out: M  = Methode, mit der Sp ab sofort dargestellt werden soll:   }
  6060. {          Display_NORMAL, Display_FAST oder Display_SHADOW         }
  6061. {rem: Existiert das Sprite noch nicht oder ist der Modus nicht er-  }
  6062. {     laubt, so geschieht nicht!                                    }
  6063. VAR ad:WORD;
  6064. BEGIN
  6065.  ad:=SPRITEAD[Sp];
  6066.  IF ad=0 THEN Error:=Err_InvalidSpriteNumber {Sprite muss schon geladen sein}
  6067.  ELSE IF (M<>Display_NORMAL) AND (M<>Display_FAST) AND (M<>Display_SHADOW)
  6068.   THEN Error:=Err_InvalidMode  {nur diese 3 Modi sind zulaessig}
  6069.  ELSE MEM[ad:Modus]:=M
  6070. END;
  6071.  
  6072. FUNCTION GetModeByte(Sp:WORD):BYTE;
  6073. { in: Sp    = Spritenummer, dessen Modusbyte abgefragt werden soll}
  6074. {out: Methode, die fuer Sp momentan gesetzt ist: Display_NORMAL,  }
  6075. {     Display_FAST, Display_SHADOW bzw. Display_UNKNOWN, wenn das }
  6076. {     Sprite noch nicht geladen wurde!}
  6077. VAR ad:WORD;
  6078. BEGIN
  6079.  ad:=SPRITEAD[Sp];
  6080.  IF (ad=0)
  6081.   THEN GetModeByte:=Display_UNKNOWN     {Sprite noch nicht geladen}
  6082.   ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
  6083. END;
  6084.  
  6085. PROCEDURE FillPage(pa,color:Byte);
  6086. { in: pa    = die Seite, die gefuellt werden soll (0..3)}
  6087. {     color = Fuellfarbe fuer die Seite}
  6088. {out: Grafikseite "pa" wurde mit der Farbe "Color" gefuellt    }
  6089. {rem: Sinnvoll sind nur die Seiten 0,1 und BACKGNDPAGE, jedoch }
  6090. {     ist SCROLLPAGE ebenfalls erlaubt}
  6091. BEGIN
  6092.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) AND (pa<>SCROLLPAGE)
  6093.   THEN Error:=Err_InvalidPageNumber
  6094.   ELSE BEGIN
  6095.         portw[$3C4]:=$0F02; {im Map-Mask Register alle 4 Ebenen selektieren}
  6096.         fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
  6097.        END;
  6098. END;
  6099.  
  6100. PROCEDURE FillBackground(color:BYTE);
  6101. { in: color = Fuellfarbe fuer die Hintergrundseite BACKGNDPAGE        }
  6102. {out: Die Grafikseite BACKGNDPAGE wurde mit der Farbe "Color" gefuellt}
  6103. {rem: Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll   }
  6104. BEGIN
  6105.  FillPage(BACKGNDPAGE,color)
  6106. END;
  6107.  
  6108. PROCEDURE GetBackgroundFromPage(pa:Byte);
  6109. {in : pa = 0 oder 1 }
  6110. {out: -             }
  6111. {rem: Der Hintergrundspeicher BACKGNDPAGE wird mit dem Inhalt der an- }
  6112. {     gegebenen Grafikseite gefuellt.}
  6113. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll   }
  6114. VAR p:POINTER;
  6115. BEGIN
  6116.  IF (pa<>0) AND (pa<>1)
  6117.   THEN Error:=Err_InvalidPageNumber
  6118.   ELSE BEGIN
  6119.         portw[$3c4]:=$0f02; {im MapMask Register alle 4 Ebenen selektieren}
  6120.         port[$3ce]:=5;      {Schreibmodus 1 }
  6121.         port[$3cf]:=port[$3cf] OR 1;   {oder direkt :=$41}
  6122.         p:=Ptr(Segment_Adr[pa],$0000);
  6123.         MOVE(p^,MEM[BACKGNDADR:0],PAGESIZE);
  6124.         portw[$3cf]:=port[$3cf] and $FC; {Schreibmodus 0 (oder direkt:=$40)}
  6125.        END;
  6126. END;
  6127.  
  6128. PROCEDURE WritePage(name:STRING; pa:BYTE);
  6129. { in: name     = Filename fuer das abzuspeichernde Bild}
  6130. {     pa       = abzuspeichernde Seite (0..2) }
  6131. {     PAGESIZE = Groesse einer Bitplane       }
  6132. {     PICHeader= einzutragende Kennung fuer Bilderdateien}
  6133. {out: - }
  6134. {rem: Die Grafik auf Seite "pa" wurde in der Datei "name" als Bitmap abgelegt}
  6135. {     Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte zu je }
  6136. {     1 Byte plus Length(PICHeader) als Kennung}
  6137. VAR f:FILE;
  6138.     i,oldMode:BYTE;
  6139.     fehler:BOOLEAN;
  6140. BEGIN
  6141.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  6142.   THEN BEGIN
  6143.         Error:=Err_InvalidPageNumber; exit
  6144.        END;
  6145.  {$I-}
  6146.  Assign(f,name); fehler:=IOResult<>0;
  6147.  Rewrite(f,1);   fehler:=fehler OR (IOResult<>0);
  6148.  BlockWrite(f,PICHeader[1],Length(PICHeader));
  6149.  fehler:=fehler OR (IOResult<>0);
  6150.  {$I+}
  6151.  IF fehler
  6152.   THEN BEGIN
  6153.         {$I-} Close(f); {$I+}
  6154.         Error:=Err_FileIO; exit
  6155.        END;
  6156.  port[$3ce]:=5;       {alten Lese-/Schreibmodus merken}
  6157.  oldMode:=port[$3cf];
  6158.  port[$3cf]:=$40;     {Lesemodus 0 setzen}
  6159.  FOR i:=0 TO 3 DO
  6160.   BEGIN
  6161.    portw[$3CE]:=4+(i shl 8); {Lese-Plane anwaehlen}
  6162.    {$I-}
  6163.    BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
  6164.    {$I+}
  6165.    fehler:=fehler OR (IOResult<>0);
  6166.   END;
  6167.  {$I-}
  6168.  Close(f);
  6169.  {$I+}
  6170.  fehler:=fehler OR (IOResult<>0);
  6171.  port[$3ce]:=5;       {alten Lese-/Schreibmodus setzen}
  6172.  port[$3cf]:=oldMode;
  6173.  IF fehler THEN Error:=Err_FileIO
  6174. END;
  6175.  
  6176. PROCEDURE LoadPage(name:STRING; pa:BYTE);
  6177. { in: name     = Filename fuer das zu ladende Bild}
  6178. {     pa       = Zielseite, in die das Bild geladen werden soll (0..2) }
  6179. {     PAGESIZE = Groesse einer Bitplane    }
  6180. {     PICHeader= Kennung fuer Bilderdateien}
  6181. {out: - }
  6182. {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Seite "pa" geladen}
  6183. VAR f:FILE;
  6184.     i,oldMode:BYTE;
  6185.     fehler:BOOLEAN;
  6186.     s:STRING[3];
  6187. BEGIN
  6188.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  6189.   THEN BEGIN
  6190.         Error:=Err_InvalidPageNumber; exit
  6191.        END;
  6192.  {$I-}
  6193.  Assign(f,name); fehler:=IOResult<>0;
  6194.  Reset(f,1);     fehler:=fehler OR (IOResult<>0);
  6195.  s[0]:=PICHeader[0];
  6196.  BlockRead(f,s[1],Length(PICHeader)); fehler:=fehler OR (IOResult<>0);
  6197.  {$I+}
  6198.  IF fehler
  6199.   THEN BEGIN
  6200.         {$I-} Close(f); {$I+}
  6201.         Error:=Err_FileIO; exit
  6202.        END
  6203.   ELSE IF (FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
  6204.   THEN BEGIN
  6205.         {$I-} Close(f); {$I+}
  6206.         Error:=Err_NoPicture; exit
  6207.        END;
  6208.  port[$3ce]:=5;       {alten Lese-/Schreibmodus merken}
  6209.  oldMode:=port[$3cf];
  6210.  port[$3cf]:=$40;     {Schreibmodus 0 setzen}
  6211.  FOR i:=0 TO 3 DO
  6212.   BEGIN
  6213.    portw[$3c4]:=2+(TranslateTab[i] shl 8); {Schreib-Plane anwaehlen}
  6214.    {$I-}
  6215.    BlockRead(f,mem[Segment_Adr[pa]:0],PAGESIZE);
  6216.    {$I+}
  6217.    fehler:=fehler OR (IOResult<>0);
  6218.   END;
  6219.  {$I-}
  6220.  Close(f);
  6221.  {$I+}
  6222.  fehler:=fehler OR (IOResult<>0);
  6223.  port[$3ce]:=5;       {alten Lese-/Schreibmodus setzen}
  6224.  port[$3cf]:=oldMode;
  6225.  IF fehler THEN Error:=Err_FileIO
  6226. END;
  6227.  
  6228. PROCEDURE WriteBackgroundPage(name:STRING);
  6229. { in: name       = Filename fuer das abzuspeichernde Hintergrundbild}
  6230. {     BACKGNDPAGE= abzuspeichernde Seite (=2) }
  6231. {     PAGESIZE   = Groesse einer Bitplane     }
  6232. {     PICHeader  = einzutragende Kennung fuer Bilderdateien}
  6233. {out: - }
  6234. {rem: Die Grafik der Hintergrundseite wurde in der Datei "name" abgelegt}
  6235. {     Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte  }
  6236. {     zu je 1 Byte plus Length(PICHeader) als Kennung}
  6237. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll     }
  6238. BEGIN
  6239.  WritePage(name,BACKGNDPAGE)
  6240. END;
  6241.  
  6242. PROCEDURE LoadBackgroundPage(name:STRING);
  6243. { in: name       = Filename fuer das zu ladende Hintergrundbild}
  6244. {     BACKGNDPAGE= Zielseite, in die das Bild geladen werden soll (=2) }
  6245. {     PAGESIZE = Groesse einer Bitplane    }
  6246. {     PICHeader= Kennung fuer Bilderdateien}
  6247. {out: - }
  6248. {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Hintergrundseite}
  6249. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll}
  6250. {     BACKGNDPAGE geladen}
  6251. BEGIN
  6252.  LoadPage(name,BACKGNDPAGE)
  6253. END;
  6254.  
  6255.  
  6256.  
  6257. PROCEDURE InitRoutines;
  6258. { in: - }
  6259. {out: SpriteN[],SPRITEAD[] wurden auf "gaenzlich leer" initialisiert     }
  6260. {     NextSprite[] wurde so gesetzt, dass jedes Sprite sein eigener Nach-}
  6261. {     folger ist}
  6262. {     PAGE, PAGEADR wurden auf die Grafikseite 0 eingestellt}
  6263. {     BACKGNDADR wurde auf die Hintergrundseite gesetzt}
  6264. {     SCROLLADR wurde auf die scrollbare Hintergrundseite gesetzt}
  6265. {     BACKGROUNDMODE wurde auf STATIC gesetzt}
  6266. {     StartVirtualX,StartVirtualY = 0 (d.h.: virtuelle = absolute Koord. }
  6267. {     oldMode = alter Grafikmodus}
  6268. {     Error wurde gesetzt, falls keine VGA-Karte im System enthalten ist }
  6269. {     CycleTime = 0, d.h.: keine Mindestzeit fuer einen Animationszyklus }
  6270. {     Color = 15, d.h.: weiss (dto.) }
  6271. {rem: Diese Prozedur sollte einmal - ganz zu Beginn - zur Initialisierung}
  6272. {     des Animationspaketes aufgerufen werden                            }
  6273. VAR i:WORD;
  6274.  
  6275.     FUNCTION IsVGA:BOOLEAN;
  6276.     BEGIN
  6277.      WITH Regs DO
  6278.       BEGIN
  6279.        AX:=$1A00;
  6280.        Intr($10,Regs);
  6281.        IsVGA:=(AL=$1A) AND    {VGA Identify-Adapter-Function unterstuetzt?}
  6282.               ( (BL=7) OR (BL=8) )  {VGAMono oder VGAColor - Adapter}
  6283.       END;
  6284.     END;
  6285.  
  6286. BEGIN
  6287.  IF IsVGA THEN Error:=Err_None
  6288.           ELSE Error:=Err_NoVGA;
  6289.  
  6290.  SetCycleTime(0);
  6291.  
  6292.  fillchar(SpriteN,sizeof(SpriteN),0);
  6293.  fillchar(SPRITEAD,sizeof(SPRITEAD),0);
  6294.  
  6295.  FOR i:=0 TO LoadMAX DO NextSprite[i]:=i;
  6296.  
  6297.  BACKGNDADR:=Segment_Adr[BACKGNDPAGE];  {Segmentadresse der Hintergrundseite}
  6298.  
  6299.  PAGE:=0;   {Seite, auf der gezeichnet werden soll}
  6300.  PAGEADR:=Segment_Adr[PAGE];
  6301.  SCROLLADR:=Segment_Adr[SCROLLPAGE];
  6302.  SetBackgroundMode(STATIC);
  6303.  
  6304.  StartVirtualX:=0; StartVirtualY:=0;    {virtuelle = absolute Koordinaten}
  6305.  Color:=white;            {aktuelle Zeichenfarbe sei Weiss }
  6306.  regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
  6307.  
  6308. END;
  6309.  
  6310. PROCEDURE CloseRoutines;
  6311. { in: oldMode = alter Grafikmodus, auf den zurueckgeschaltet werden soll}
  6312. {out: - }
  6313. BEGIN
  6314.  regs.al:=oldMode; regs.ah:=0; intr($10,regs);
  6315. END;
  6316.  
  6317. FUNCTION GetErrorMessage:STRING;
  6318. { in: Error = Nummer des aufgetretenen Fehlers}
  6319. {out: den Fehler in Worten}
  6320. BEGIN
  6321.  CASE Error OF
  6322.   Err_None:GetErrorMessage:='No Error';
  6323.   Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
  6324.   Err_FileIO:GetErrorMessage:='I/O-error with file';
  6325.   Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
  6326.   Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
  6327.   Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
  6328.   Err_NoVGA:GetErrorMessage:='No VGA-card found';
  6329.   Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
  6330.   Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
  6331.   Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
  6332.   Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
  6333.   Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
  6334.   Err_BackgroundToBig:GetErrorMessage:='Background too big for tile-buffer';
  6335.   Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
  6336.   Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
  6337.   ELSE GetErrorMessage:='Unknown error';
  6338.  END;
  6339. END;
  6340.  
  6341.  
  6342. BEGIN
  6343.  
  6344.  InitRoutines;
  6345.  
  6346. END.
  6347.